Add NetworkPkg (P.UDK2010.UP3.Network.P1)

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
hhtian
2010-11-01 06:13:54 +00:00
parent 12873d5766
commit a3bcde70e6
142 changed files with 83988 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
/** @file
Implementation of protocols EFI_COMPONENT_NAME_PROTOCOL and
EFI_COMPONENT_NAME2_PROTOCOL.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
//
// EFI Component Name Functions
//
/**
Retrieves a Unicode string that is the user-readable name of the driver.
This function retrieves the user-readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user-readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] DriverName A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This, and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language or DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
TcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user-readable name of the controller
that is being managed by a driver.
This function retrieves the user-readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user-readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] ControllerHandle The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param[in] ChildHandle The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] ControllerName A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language, from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user-readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language or ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
TcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
///
/// EFI Component Name Protocol
///
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gTcpComponentName = {
TcpComponentNameGetDriverName,
TcpComponentNameGetControllerName,
"eng"
};
///
/// EFI Component Name 2 Protocol
///
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gTcpComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) TcpComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) TcpComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mTcpDriverNameTable[] = {
{
"eng;en",
L"TCP Network Service Driver"
},
{
NULL,
NULL
}
};
/**
Retrieves a Unicode string that is the user-readable name of the driver.
This function retrieves the user-readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user-readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] DriverName A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This, and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language or DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
TcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mTcpDriverNameTable,
DriverName,
(BOOLEAN) (This == &gTcpComponentName)
);
}
/**
Retrieves a Unicode string that is the user-readable name of the controller
that is being managed by a driver.
This function retrieves the user-readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user-readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] ControllerHandle The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param[in] ChildHandle The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] ControllerName A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language, from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user-readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language or ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
TcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
return EFI_UNSUPPORTED;
}

1230
NetworkPkg/TcpDxe/SockImpl.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
/** @file
The function declaration that provided for Socket Interface.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SOCK_IMPL_H_
#define _SOCK_IMPL_H_
#include "Socket.h"
/**
Signal a event with the given status.
@param[in] Token The token's event is to be signaled.
@param[in] TokenStatus The status to be sent with the event.
**/
#define SIGNAL_TOKEN(Token, TokenStatus) \
do { \
(Token)->Status = (TokenStatus); \
gBS->SignalEvent ((Token)->Event); \
} while (0)
#define SOCK_HEADER_SPACE (60 + 60 + 72)
/**
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
);
/**
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
);
/**
Flush the sndBuffer and rcvBuffer of socket.
@param[in, out] Sock Pointer to the socket.
**/
VOID
SockConnFlush (
IN OUT SOCKET *Sock
);
/**
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 exception occured.
**/
SOCKET *
SockCreate (
IN SOCK_INIT_DATA *SockInitData
);
/**
Destroy a socket.
@param[in, out] Sock Pointer to the socket.
**/
VOID
SockDestroy (
IN OUT SOCKET *Sock
);
#endif

View File

@@ -0,0 +1,999 @@
/** @file
Interface function of the Socket.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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[in] List Pointer to the token list to be searched.
@param[in] 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[in] Sock Pointer to the instance's socket.
@param[in] 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 the socket Sock.
@param[in] Sock Pointer to the instance's socket.
@param[in] List Pointer to the list to store the token.
@param[in] Token Pointer to the token to be buffered.
@param[in] DataLen The data length of the buffer contained in Token.
@return Pointer to the token that wraps Token. If NULL, an error condition occurred.
**/
SOCK_TOKEN *
SockBufferToken (
IN SOCKET *Sock,
IN LIST_ENTRY *List,
IN VOID *Token,
IN UINT32 DataLen
)
{
SOCK_TOKEN *SockToken;
SockToken = AllocateZeroPool (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[in, out] Sock The socket to be destroyed.
@retval EFI_SUCCESS The socket Sock was destroyed successfully.
@retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
**/
EFI_STATUS
SockDestroyChild (
IN OUT 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[in] SockInitData Inital data to setting the socket.
@return Pointer to the newly created socket. If NULL, an 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[in] Sock Pointer to the socket to be configured.
@param[in] ConfigData Pointer to the configuration data.
@retval EFI_SUCCESS The socket 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[in] Sock Pointer to the socket to initiate the initate the
connection.
@param[in] Token Pointer to the token used for the connection
operation.
@retval EFI_SUCCESS The connection 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[in] Sock Pointer to the socket to accept connections.
@param[in] 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 limits.
**/
EFI_STATUS
SockAccept (
IN SOCKET *Sock,
IN VOID *Token
)
{
EFI_TCP4_LISTEN_TOKEN *ListenToken;
LIST_ENTRY *ListEntry;
EFI_STATUS Status;
SOCKET *Socket;
EFI_EVENT Event;
ASSERT (SockStream == Sock->Type);
Status = EfiAcquireLockOrFail (&(Sock->Lock));
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockAccept: Get the access for socket failed with %r",
Status)
);
return EFI_ACCESS_DENIED;
}
if (SOCK_IS_NO_MAPPING (Sock)) {
Status = EFI_NO_MAPPING;
goto Exit;
}
if (SOCK_IS_UNCONFIGURED (Sock)) {
Status = EFI_NOT_STARTED;
goto Exit;
}
if (!SOCK_IS_LISTENING (Sock)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
if (SockTokenExisted (Sock, Event)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;
//
// Check if a connection has already in this Sock->ConnectionList
//
NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {
Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);
if (SOCK_IS_CONNECTED (Socket)) {
ListenToken->NewChildHandle = Socket->SockHandle;
SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);
RemoveEntryList (ListEntry);
ASSERT (Socket->Parent != NULL);
Socket->Parent->ConnCnt--;
DEBUG (
(EFI_D_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[in] Sock Pointer to the socket to process the token with
data.
@param[in] Token The token with data that needs to send out.
@retval EFI_SUCCESS The token 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 limits.
**/
EFI_STATUS
SockSend (
IN SOCKET *Sock,
IN VOID *Token
)
{
SOCK_IO_TOKEN *SndToken;
EFI_EVENT Event;
UINT32 FreeSpace;
EFI_TCP4_TRANSMIT_DATA *TxData;
EFI_STATUS Status;
SOCK_TOKEN *SockToken;
UINT32 DataLen;
ASSERT (SockStream == Sock->Type);
Status = EfiAcquireLockOrFail (&(Sock->Lock));
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockSend: Get the access for socket failed with %r",
Status)
);
return EFI_ACCESS_DENIED;
}
if (SOCK_IS_NO_MAPPING (Sock)) {
Status = EFI_NO_MAPPING;
goto Exit;
}
SndToken = (SOCK_IO_TOKEN *) Token;
TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;
if (SOCK_IS_UNCONFIGURED (Sock)) {
Status = EFI_NOT_STARTED;
goto Exit;
}
if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
//
// check if a token is already in the token buffer
//
Event = SndToken->Token.Event;
if (SockTokenExisted (Sock, Event)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
DataLen = TxData->DataLength;
//
// process this sending token now or buffer it only?
//
FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);
if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {
SockToken = SockBufferToken (
Sock,
&Sock->SndTokenList,
SndToken,
DataLen
);
if (NULL == SockToken) {
Status = EFI_OUT_OF_RESOURCES;
}
} else {
SockToken = SockBufferToken (
Sock,
&Sock->ProcessingSndTokenList,
SndToken,
DataLen
);
if (NULL == SockToken) {
DEBUG (
(EFI_D_ERROR,
"SockSend: Failed to buffer IO token into socket processing SndToken List\n",
Status)
);
Status = EFI_OUT_OF_RESOURCES;
goto Exit;
}
Status = SockProcessTcpSndData (Sock, TxData);
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockSend: Failed to process Snd Data\n",
Status)
);
RemoveEntryList (&(SockToken->TokenList));
FreePool (SockToken);
}
}
Exit:
EfiReleaseLock (&(Sock->Lock));
return Status;
}
/**
Issue a token to get data from the socket.
@param[in] Sock Pointer to the socket to get data from.
@param[in] Token The token to store the received data from the
socket.
@retval EFI_SUCCESS The token processed successfully.
@retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
socket is closed, or the socket is not in a
synchronized state , or the token is already in one
of this socket's lists.
@retval EFI_NO_MAPPING The IP address configuration operation is not
finished.
@retval EFI_NOT_STARTED The socket is not configured.
@retval EFI_CONNECTION_FIN The connection is closed and there is no more data.
@retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.
**/
EFI_STATUS
SockRcv (
IN SOCKET *Sock,
IN VOID *Token
)
{
SOCK_IO_TOKEN *RcvToken;
UINT32 RcvdBytes;
EFI_STATUS Status;
EFI_EVENT Event;
ASSERT (SockStream == Sock->Type);
Status = EfiAcquireLockOrFail (&(Sock->Lock));
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockRcv: Get the access for socket failed with %r",
Status)
);
return EFI_ACCESS_DENIED;
}
if (SOCK_IS_NO_MAPPING (Sock)) {
Status = EFI_NO_MAPPING;
goto Exit;
}
if (SOCK_IS_UNCONFIGURED (Sock)) {
Status = EFI_NOT_STARTED;
goto Exit;
}
if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
RcvToken = (SOCK_IO_TOKEN *) Token;
//
// check if a token is already in the token buffer of this socket
//
Event = RcvToken->Token.Event;
if (SockTokenExisted (Sock, Event)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
RcvToken = (SOCK_IO_TOKEN *) Token;
RcvdBytes = GET_RCV_DATASIZE (Sock);
//
// check whether an error has happened before
//
if (EFI_ABORTED != Sock->SockError) {
SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);
Sock->SockError = EFI_ABORTED;
goto Exit;
}
//
// check whether can not receive and there is no any
// data buffered in Sock->RcvBuffer
//
if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {
Status = EFI_CONNECTION_FIN;
goto Exit;
}
if (RcvdBytes != 0) {
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[in, out] 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 OUT SOCKET *Sock
)
{
EFI_STATUS Status;
ASSERT (SockStream == Sock->Type);
Status = EfiAcquireLockOrFail (&(Sock->Lock));
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockFlush: Get the access for socket failed with %r",
Status)
);
return EFI_ACCESS_DENIED;
}
if (!SOCK_IS_CONFIGURED (Sock)) {
Status = EFI_ACCESS_DENIED;
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[in, out] Sock Pointer to the socket of the connection to close
or abort.
@param[in] Token The token for a close operation.
@param[in] OnAbort TRUE for aborting the connection; FALSE to close it.
@retval EFI_SUCCESS The close or abort operation 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 OUT SOCKET *Sock,
IN VOID *Token,
IN BOOLEAN OnAbort
)
{
EFI_STATUS Status;
EFI_EVENT Event;
ASSERT (SockStream == Sock->Type);
Status = EfiAcquireLockOrFail (&(Sock->Lock));
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"SockClose: Get the access for socket failed with %r",
Status)
);
return EFI_ACCESS_DENIED;
}
if (SOCK_IS_NO_MAPPING (Sock)) {
Status = EFI_NO_MAPPING;
goto Exit;
}
if (SOCK_IS_UNCONFIGURED (Sock)) {
Status = EFI_NOT_STARTED;
goto Exit;
}
if (SOCK_IS_DISCONNECTING (Sock)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
if (SockTokenExisted (Sock, Event)) {
Status = EFI_ACCESS_DENIED;
goto Exit;
}
Sock->CloseToken = Token;
SockSetState (Sock, SO_DISCONNECTING);
if (OnAbort) {
Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);
} else {
Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);
}
Exit:
EfiReleaseLock (&(Sock->Lock));
return Status;
}
/**
Get the mode data of the low layer protocol.
@param[in] Sock Pointer to the socket to get mode data from.
@param[in, out] Mode Pointer to the data to store the low layer mode
information.
@retval EFI_SUCCESS The mode data was obtained 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[in] Sock Pointer to the socket of the connection to join the
specific multicast group.
@param[in] GroupInfo Pointer to the multicast group info.
@retval EFI_SUCCESS The configuration completed 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[in] Sock Pointer to the socket associated with the IP route
table to operate on.
@param[in] RouteInfo Pointer to the route information to be processed.
@retval EFI_SUCCESS The route table 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;
}

924
NetworkPkg/TcpDxe/Socket.h Normal file
View File

@@ -0,0 +1,924 @@
/** @file
Common head file for TCP socket.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <Uefi.h>
#include <Protocol/Tcp4.h>
#include <Protocol/Tcp6.h>
#include <Library/NetLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/DpcLib.h>
#define SOCK_SND_BUF 0
#define SOCK_RCV_BUF 1
#define SOCK_BUFF_LOW_WATER (2 * 1024)
#define SOCK_RCV_BUFF_SIZE (8 * 1024)
#define SOCK_SND_BUFF_SIZE (8 * 1024)
#define SOCK_BACKLOG 5
#define PROTO_RESERVED_LEN 20
#define SO_NO_MORE_DATA 0x0001
//
//
//
// When a socket is created it enters into SO_UNCONFIGURED,
// no actions can be taken on this socket, only after calling
// SockConfigure. The state transition diagram of socket is
// as following:
//
// SO_UNCONFIGURED --- SO_CONFIGURED --- SO_CONNECTING
// ^ | |
// | ---> SO_LISTENING |
// | |
// |------------------SO_DISCONNECTING<-- SO_CONNECTED
//
// A passive socket can only go into SO_LISTENING and
// SO_UNCONFIGURED state. SO_XXXING state is a middle state
// when a socket is undergoing a protocol procedure such
// as requesting a TCP connection.
//
//
//
///
/// Socket state
///
#define SO_CLOSED 0
#define SO_LISTENING 1
#define SO_CONNECTING 2
#define SO_CONNECTED 3
#define SO_DISCONNECTING 4
///
/// Socket configure state
///
#define SO_UNCONFIGURED 0
#define SO_CONFIGURED_ACTIVE 1
#define SO_CONFIGURED_PASSIVE 2
#define SO_NO_MAPPING 3
///
/// The request issued from socket layer to protocol layer.
///
#define SOCK_ATTACH 0 ///< Attach current socket to a new PCB
#define SOCK_DETACH 1 ///< Detach current socket from the PCB
#define SOCK_CONFIGURE 2 ///< Configure attached PCB
#define SOCK_FLUSH 3 ///< Flush attached PCB
#define SOCK_SND 4 ///< Need protocol to send something
#define SOCK_SNDPUSH 5 ///< Need protocol to send pushed data
#define SOCK_SNDURG 6 ///< Need protocol to send urgent data
#define SOCK_CONSUMED 7 ///< Application has retrieved data from socket
#define SOCK_CONNECT 8 ///< Need to connect to a peer
#define SOCK_CLOSE 9 ///< Need to close the protocol process
#define SOCK_ABORT 10 ///< Need to reset the protocol process
#define SOCK_POLL 11 ///< Need to poll to the protocol layer
#define SOCK_ROUTE 12 ///< Need to add a route information
#define SOCK_MODE 13 ///< Need to get the mode data of the protocol
#define SOCK_GROUP 14 ///< Need to join a mcast group
/**
Set socket SO_NO_MORE_DATA flag.
@param[in] Sock Pointer to the socket
**/
#define SOCK_NO_MORE_DATA(Sock) ((Sock)->Flag |= SO_NO_MORE_DATA)
/**
Check whether the socket is unconfigured.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is unconfigued.
@retval FALSE The socket is not unconfigued.
**/
#define SOCK_IS_UNCONFIGURED(Sock) ((Sock)->ConfigureState == SO_UNCONFIGURED)
/**
Check whether the socket is configured.
@param[in] Sock Pointer to the socket
@retval TRUE The socket is configued
@retval FALSE The socket is not configued
**/
#define SOCK_IS_CONFIGURED(Sock) \
(((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE) || \
((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE))
/**
Check whether the socket is configured to active mode.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is configued to active mode.
@retval FALSE The socket is not configued to active mode.
**/
#define SOCK_IS_CONFIGURED_ACTIVE(Sock) ((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE)
/**
Check whether the socket is configured to passive mode.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is configued to passive mode.
@retval FALSE The socket is not configued to passive mode.
**/
#define SOCK_IS_CONNECTED_PASSIVE(Sock) ((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE)
/**
Check whether the socket is mapped.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is not mapping.
@retval FALSE The socket is mapped.
**/
#define SOCK_IS_NO_MAPPING(Sock) ((Sock)->ConfigureState == SO_NO_MAPPING)
/**
Check whether the socket is closed.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is closed.
@retval FALSE The socket is not closed.
**/
#define SOCK_IS_CLOSED(Sock) ((Sock)->State == SO_CLOSED)
/**
Check whether the socket is listening.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is listening.
@retval FALSE The socket is not listening.
**/
#define SOCK_IS_LISTENING(Sock) ((Sock)->State == SO_LISTENING)
/**
Check whether the socket is connecting.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is connecting.
@retval FALSE The socket is not connecting.
**/
#define SOCK_IS_CONNECTING(Sock) ((Sock)->State == SO_CONNECTING)
/**
Check whether the socket has connected.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket has connected.
@retval FALSE The socket has not connected.
**/
#define SOCK_IS_CONNECTED(Sock) ((Sock)->State == SO_CONNECTED)
/**
Check whether the socket is disconnecting.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is disconnecting.
@retval FALSE The socket is not disconnecting.
**/
#define SOCK_IS_DISCONNECTING(Sock) ((Sock)->State == SO_DISCONNECTING)
/**
Check whether the socket is no more data.
@param[in] Sock Pointer to the socket.
@retval TRUE The socket is no more data.
@retval FALSE The socket still has data.
**/
#define SOCK_IS_NO_MORE_DATA(Sock) (0 != ((Sock)->Flag & SO_NO_MORE_DATA))
/**
Set the size of the receive buffer.
@param[in] Sock Pointer to the socket.
@param[in] Size The size to set.
**/
#define SET_RCV_BUFFSIZE(Sock, Size) ((Sock)->RcvBuffer.HighWater = (Size))
/**
Get the size of the receive buffer.
@param[in] Sock Pointer to the socket.
@return The receive buffer size.
**/
#define GET_RCV_BUFFSIZE(Sock) ((Sock)->RcvBuffer.HighWater)
/**
Get the size of the receive data.
@param[in] Sock Pointer to the socket.
@return The received data size.
**/
#define GET_RCV_DATASIZE(Sock) (((Sock)->RcvBuffer.DataQueue)->BufSize)
/**
Set the size of the send buffer.
@param[in] Sock Pointer to the socket.
@param[in] Size The size to set.
**/
#define SET_SND_BUFFSIZE(Sock, Size) ((Sock)->SndBuffer.HighWater = (Size))
/**
Get the size of the send buffer.
@param[in] Sock Pointer to the socket.
@return The send buffer size.
**/
#define GET_SND_BUFFSIZE(Sock) ((Sock)->SndBuffer.HighWater)
/**
Get the size of the send data.
@param[in] Sock Pointer to the socket.
@return The send data size.
**/
#define GET_SND_DATASIZE(Sock) (((Sock)->SndBuffer.DataQueue)->BufSize)
/**
Set the backlog value of the socket.
@param[in] Sock Pointer to the socket.
@param[in] Value The value to set.
**/
#define SET_BACKLOG(Sock, Value) ((Sock)->BackLog = (Value))
/**
Get the backlog value of the socket.
@param[in] Sock Pointer to the socket.
@return The backlog value.
**/
#define GET_BACKLOG(Sock) ((Sock)->BackLog)
/**
Set the socket with error state.
@param[in] Sock Pointer to the socket.
@param[in] Error The error state.
**/
#define SOCK_ERROR(Sock, Error) ((Sock)->SockError = (Error))
#define SOCK_SIGNATURE SIGNATURE_32 ('S', 'O', 'C', 'K')
#define SOCK_FROM_THIS(a) CR ((a), SOCKET, NetProtocol, SOCK_SIGNATURE)
#define SOCK_FROM_TOKEN(Token) (((SOCK_TOKEN *) (Token))->Sock)
#define PROTO_TOKEN_FORM_SOCK(SockToken, Type) ((Type *) (((SOCK_TOKEN *) (SockToken))->Token))
typedef struct _TCP_SOCKET SOCKET;
///
/// Socket completion token
///
typedef struct _SOCK_COMPLETION_TOKEN {
EFI_EVENT Event; ///< The event to be issued
EFI_STATUS Status; ///< The status to be issued
} SOCK_COMPLETION_TOKEN;
typedef union {
VOID *RxData;
VOID *TxData;
} SOCK_IO_DATA;
///
/// The application token with data packet
///
typedef struct _SOCK_IO_TOKEN {
SOCK_COMPLETION_TOKEN Token;
SOCK_IO_DATA Packet;
} SOCK_IO_TOKEN;
///
/// The socket type.
///
typedef enum {
SockDgram, ///< This socket providing datagram service
SockStream ///< This socket providing stream service
} SOCK_TYPE;
///
/// The buffer structure of rcvd data and send data used by socket.
///
typedef struct _SOCK_BUFFER {
UINT32 HighWater; ///< The buffersize upper limit of sock_buffer
UINT32 LowWater; ///< The low warter mark of sock_buffer
NET_BUF_QUEUE *DataQueue; ///< The queue to buffer data
} SOCK_BUFFER;
/**
The handler of protocol for request from socket.
@param[in] Socket The socket issuing the request to protocol.
@param[in] Request The request issued by socket.
@param[in] RequestData The request related data.
@retval EFI_SUCCESS The socket request is completed successfully.
@retval other The error status returned by the corresponding TCP
layer function.
**/
typedef
EFI_STATUS
(*SOCK_PROTO_HANDLER) (
IN SOCKET *Socket,
IN UINT8 Request,
IN VOID *RequestData
);
/**
The Callback funtion called after the TCP socket is created.
@param[in] This Pointer to the socket just created.
@param[in] Context Context of the socket.
@retval EFI_SUCCESS This protocol installed successfully.
@retval other Some error occured.
**/
typedef
EFI_STATUS
(*SOCK_CREATE_CALLBACK) (
IN SOCKET *This,
IN VOID *Context
);
/**
The callback function called before the TCP socket is to be destroyed.
@param[in] This The TCP socket to be destroyed.
@param[in] Context The context.
**/
typedef
VOID
(*SOCK_DESTROY_CALLBACK) (
IN SOCKET *This,
IN VOID *Context
);
///
/// The initialize data for create a new socket.
///
typedef struct _SOCK_INIT_DATA {
SOCK_TYPE Type;
UINT8 State;
SOCKET *Parent; ///< The parent of this socket
UINT32 BackLog; ///< The connection limit for listening socket
UINT32 SndBufferSize; ///< The high warter mark of send buffer
UINT32 RcvBufferSize; ///< The high warter mark of receive buffer
UINT8 IpVersion;
VOID *Protocol; ///< The pointer to protocol function template
///< wanted to install on socket
//
// Callbacks after socket is created and before socket is to be destroyed.
//
SOCK_CREATE_CALLBACK CreateCallback; ///< Callback after created
SOCK_DESTROY_CALLBACK DestroyCallback; ///< Callback before destroied
VOID *Context; ///< The context of the callback
//
// Opaque protocol data.
//
VOID *ProtoData;
UINT32 DataSize;
SOCK_PROTO_HANDLER ProtoHandler; ///< The handler of protocol for socket request
EFI_HANDLE DriverBinding; ///< The driver binding handle
} SOCK_INIT_DATA;
///
/// The union type of TCP and UDP protocol.
///
typedef union _NET_PROTOCOL {
EFI_TCP4_PROTOCOL Tcp4Protocol; ///< Tcp4 protocol
EFI_TCP6_PROTOCOL Tcp6Protocol; ///< Tcp6 protocol
} NET_PROTOCOL;
///
/// The socket structure representing a network service access point.
///
struct _TCP_SOCKET {
//
// Socket description information
//
UINT32 Signature; ///< Signature of the socket
EFI_HANDLE SockHandle; ///< The virtual handle of the socket
EFI_HANDLE DriverBinding; ///< Socket's driver binding protocol
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
LIST_ENTRY Link;
UINT8 ConfigureState;
SOCK_TYPE Type;
UINT8 State;
UINT16 Flag;
EFI_LOCK Lock; ///< The lock of socket
SOCK_BUFFER SndBuffer; ///< Send buffer of application's data
SOCK_BUFFER RcvBuffer; ///< Receive buffer of received data
EFI_STATUS SockError; ///< The error returned by low layer protocol
BOOLEAN IsDestroyed;
//
// Fields used to manage the connection request
//
UINT32 BackLog; ///< the limit of connection to this socket
UINT32 ConnCnt; ///< the current count of connections to it
SOCKET *Parent; ///< listening parent that accept the connection
LIST_ENTRY ConnectionList; ///< the connections maintained by this socket
//
// The queue to buffer application's asynchronous token
//
LIST_ENTRY ListenTokenList;
LIST_ENTRY RcvTokenList;
LIST_ENTRY SndTokenList;
LIST_ENTRY ProcessingSndTokenList;
SOCK_COMPLETION_TOKEN *ConnectionToken; ///< app's token to signal if connected
SOCK_COMPLETION_TOKEN *CloseToken; ///< app's token to signal if closed
//
// Interface for low level protocol
//
SOCK_PROTO_HANDLER ProtoHandler; ///< The request handler of protocol
UINT8 ProtoReserved[PROTO_RESERVED_LEN]; ///< Data fields reserved for protocol
UINT8 IpVersion;
NET_PROTOCOL NetProtocol; ///< TCP or UDP protocol socket used
//
// Callbacks after socket is created and before socket is to be destroyed.
//
SOCK_CREATE_CALLBACK CreateCallback; ///< Callback after created
SOCK_DESTROY_CALLBACK DestroyCallback; ///< Callback before destroied
VOID *Context; ///< The context of the callback
};
///
/// The token structure buffered in socket layer.
///
typedef struct _SOCK_TOKEN {
LIST_ENTRY TokenList; ///< The entry to add in the token list
SOCK_COMPLETION_TOKEN *Token; ///< The application's token
UINT32 RemainDataLen; ///< Unprocessed data length
SOCKET *Sock; ///< The poninter to the socket this token
///< belongs to
} SOCK_TOKEN;
///
/// Reserved data to access the NET_BUF delivered by TCP driver.
///
typedef struct _TCP_RSV_DATA {
UINT32 UrgLen;
} TCP_RSV_DATA;
//
// Socket provided oprerations for low layer protocol implemented in SockImpl.c
//
/**
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
);
/**
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
);
/**
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
);
/**
Called by the low layer protocol to indicate that 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
);
/**
Called by low layer protocol to indicate that some data is 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
);
/**
Called by the low layer protocol to copy some data in 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
);
/**
Called by the low layer protocol to deliver received data to socket layer.
This function appends the data to the socket receive buffer, set the
urgent data length, then checks 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
);
/**
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
);
/**
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
);
//
// Socket provided operations for user interface implemented in SockInterface.c
//
/**
Create a socket and its associated protocol control block
with the intial data SockInitData and protocol specific
data ProtoData.
@param[in] SockInitData Inital data to setting the socket.
@return Pointer to the newly created socket. If NULL, an error condition occured.
**/
SOCKET *
SockCreateChild (
IN SOCK_INIT_DATA *SockInitData
);
/**
Destory the socket Sock and its associated protocol control block.
@param[in, out] Sock The socket to be destroyed.
@retval EFI_SUCCESS The socket Sock was destroyed successfully.
@retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
**/
EFI_STATUS
SockDestroyChild (
IN OUT SOCKET *Sock
);
/**
Configure the specific socket Sock using configuration data ConfigData.
@param[in] Sock Pointer to the socket to be configured.
@param[in] ConfigData Pointer to the configuration data.
@retval EFI_SUCCESS The socket 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
);
/**
Initiate a connection establishment process.
@param[in] Sock Pointer to the socket to initiate the initate the
connection.
@param[in] Token Pointer to the token used for the connection
operation.
@retval EFI_SUCCESS The connection 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
);
/**
Issue a listen token to get an existed connected network instance,
or wait for a connection if there is none.
@param[in] Sock Pointer to the socket to accept connections.
@param[in] Token The token to accept a connection.
@retval EFI_SUCCESS Either a connection is accepted or the Token is
buffered for further acceptance.
@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
);
/**
Issue a token with data to the socket to send out.
@param[in] Sock Pointer to the socket to process the token with
data.
@param[in] Token The token with data that needs to send out.
@retval EFI_SUCCESS The token 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 a memory limit.
**/
EFI_STATUS
SockSend (
IN SOCKET *Sock,
IN VOID *Token
);
/**
Issue a token to get data from the socket.
@param[in] Sock Pointer to the socket to get data from.
@param[in] Token The token to store the received data from the
socket.
@retval EFI_SUCCESS The token 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 a memory limit.
**/
EFI_STATUS
SockRcv (
IN SOCKET *Sock,
IN VOID *Token
);
/**
Reset the socket and its associated protocol control block.
@param[in, out] Sock Pointer to the socket to be flushed.
@retval EFI_SUCCESS The socket flushed successfully.
@retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
**/
EFI_STATUS
SockFlush (
IN OUT SOCKET *Sock
);
/**
Close or abort the socket associated connection.
@param[in, out] Sock Pointer to the socket of the connection to close
or abort.
@param[in] Token The token for close operation.
@param[in] OnAbort TRUE for aborting the connection, FALSE to close it.
@retval EFI_SUCCESS The close or abort operation 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 OUT SOCKET *Sock,
IN VOID *Token,
IN BOOLEAN OnAbort
);
/**
Get the mode data of the low layer protocol.
@param[in] Sock Pointer to the socket to get mode data from.
@param[in, out] Mode Pointer to the data to store the low layer mode
information.
@retval EFI_SUCCESS The mode data was obtained successfully.
@retval EFI_NOT_STARTED The socket is not configured.
**/
EFI_STATUS
SockGetMode (
IN SOCKET *Sock,
IN OUT VOID *Mode
);
/**
Configure the low level protocol to join a multicast group for
this socket's connection.
@param[in] Sock Pointer to the socket of the connection to join the
specific multicast group.
@param[in] GroupInfo Pointer to the multicast group information.
@retval EFI_SUCCESS The configuration completed 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
);
/**
Add or remove route information in IP route table associated
with this socket.
@param[in] Sock Pointer to the socket associated with the IP route
table to operate on.
@param[in] RouteInfo Pointer to the route information to be processed.
@retval EFI_SUCCESS The route table 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
);
#endif

View File

@@ -0,0 +1,861 @@
/** @file
The implementation of a dispatch routine for processing TCP requests.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
/**
Add or remove a route entry in the IP route table associated with this TCP instance.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] RouteInfo Pointer to the route information to be processed.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED The driver instance has not been started.
@retval EFI_NO_MAPPING When using the default address, configuration(DHCP,
BOOTP, RARP, etc.) is not finished yet.
@retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
@retval EFI_NOT_FOUND This route is not in the routing table
(when RouteInfo->DeleteRoute is TRUE).
@retval EFI_ACCESS_DENIED The route is already defined in the routing table
(when RouteInfo->DeleteRoute is FALSE).
**/
EFI_STATUS
Tcp4Route (
IN TCP_CB *Tcb,
IN TCP4_ROUTE_INFO *RouteInfo
)
{
IP_IO_IP_PROTOCOL Ip;
Ip = Tcb->IpInfo->Ip;
ASSERT (Ip.Ip4!= NULL);
return Ip.Ip4->Routes (
Ip.Ip4,
RouteInfo->DeleteRoute,
RouteInfo->SubnetAddress,
RouteInfo->SubnetMask,
RouteInfo->GatewayAddress
);
}
/**
Get the operational settings of this TCPv4 instance.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in, out] Mode Pointer to the buffer to store the operational
settings.
@retval EFI_SUCCESS The mode data was read.
@retval EFI_NOT_STARTED No configuration data is available because this
instance hasn't been started.
**/
EFI_STATUS
Tcp4GetMode (
IN TCP_CB *Tcb,
IN OUT TCP4_MODE_DATA *Mode
)
{
SOCKET *Sock;
EFI_TCP4_CONFIG_DATA *ConfigData;
EFI_TCP4_ACCESS_POINT *AccessPoint;
EFI_TCP4_OPTION *Option;
EFI_IP4_PROTOCOL *Ip;
Sock = Tcb->Sk;
if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
return EFI_NOT_STARTED;
}
if (Mode->Tcp4State != NULL) {
*(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
}
if (Mode->Tcp4ConfigData != NULL) {
ConfigData = Mode->Tcp4ConfigData;
AccessPoint = &(ConfigData->AccessPoint);
Option = ConfigData->ControlOption;
ConfigData->TypeOfService = Tcb->Tos;
ConfigData->TimeToLive = Tcb->Ttl;
AccessPoint->UseDefaultAddress = Tcb->UseDefaultAddr;
CopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
AccessPoint->SubnetMask = Tcb->SubnetMask;
AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
CopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);
AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);
if (Option != NULL) {
Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk);
Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk);
Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk);
Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ;
Option->DataRetries = Tcb->MaxRexmit;
Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ;
Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
Option->KeepAliveProbes = Tcb->MaxKeepAlive;
Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ;
Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
Option->EnableNagle = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
Option->EnableTimeStamp = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
Option->EnableSelectiveAck = FALSE;
Option->EnablePathMtuDiscovery = FALSE;
}
}
Ip = Tcb->IpInfo->Ip.Ip4;
ASSERT (Ip != NULL);
return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
}
/**
Get the operational settings of this TCPv6 instance.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in, out] Mode Pointer to the buffer to store the operational
settings.
@retval EFI_SUCCESS The mode data was read.
@retval EFI_NOT_STARTED No configuration data is available because this
instance hasn't been started.
**/
EFI_STATUS
Tcp6GetMode (
IN TCP_CB *Tcb,
IN OUT TCP6_MODE_DATA *Mode
)
{
SOCKET *Sock;
EFI_TCP6_CONFIG_DATA *ConfigData;
EFI_TCP6_ACCESS_POINT *AccessPoint;
EFI_TCP6_OPTION *Option;
EFI_IP6_PROTOCOL *Ip;
Sock = Tcb->Sk;
if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) {
return EFI_NOT_STARTED;
}
if (Mode->Tcp6State != NULL) {
*(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State);
}
if (Mode->Tcp6ConfigData != NULL) {
ConfigData = Mode->Tcp6ConfigData;
AccessPoint = &(ConfigData->AccessPoint);
Option = ConfigData->ControlOption;
ConfigData->TrafficClass = Tcb->Tos;
ConfigData->HopLimit = Tcb->Ttl;
AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);
AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);
IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
if (Option != NULL) {
Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk);
Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk);
Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk);
Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ;
Option->DataRetries = Tcb->MaxRexmit;
Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ;
Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
Option->KeepAliveProbes = Tcb->MaxKeepAlive;
Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ;
Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
Option->EnableNagle = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
Option->EnableTimeStamp = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
Option->EnableSelectiveAck = FALSE;
Option->EnablePathMtuDiscovery = FALSE;
}
}
Ip = Tcb->IpInfo->Ip.Ip6;
ASSERT (Ip != NULL);
return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData);
}
/**
If TcpAp->StationPort isn't zero, check whether the access point
is registered, else generate a random station port for this
access point.
@param[in] TcpAp Pointer to the access point.
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6
@retval EFI_SUCCESS The check passed or the port is assigned.
@retval EFI_INVALID_PARAMETER The non-zero station port is already used.
@retval EFI_OUT_OF_RESOURCES No port can be allocated.
**/
EFI_STATUS
TcpBind (
IN TCP_ACCESS_POINT *TcpAp,
IN UINT8 IpVersion
)
{
BOOLEAN Cycle;
EFI_IP_ADDRESS Local;
UINT16 *Port;
UINT16 *RandomPort;
if (IpVersion == IP_VERSION_4) {
CopyMem (&Local, &TcpAp->Tcp4Ap.StationAddress, sizeof (EFI_IPv4_ADDRESS));
Port = &TcpAp->Tcp4Ap.StationPort;
RandomPort = &mTcp4RandomPort;
} else {
IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress);
Port = &TcpAp->Tcp6Ap.StationPort;
RandomPort = &mTcp6RandomPort;
}
if (0 != *Port) {
//
// Check if a same endpoing is bound.
//
if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) {
return EFI_INVALID_PARAMETER;
}
} else {
//
// generate a random port
//
Cycle = FALSE;
if (TCP_PORT_USER_RESERVED == *RandomPort) {
*RandomPort = TCP_PORT_KNOWN;
}
(*RandomPort)++;
while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) {
(*RandomPort)++;
if (*RandomPort <= TCP_PORT_KNOWN) {
if (Cycle) {
DEBUG (
(EFI_D_ERROR,
"TcpBind: no port can be allocated for this pcb\n")
);
return EFI_OUT_OF_RESOURCES;
}
*RandomPort = TCP_PORT_KNOWN + 1;
Cycle = TRUE;
}
}
*Port = *RandomPort;
}
return EFI_SUCCESS;
}
/**
Flush the Tcb add its associated protocols.
@param[in, out] Tcb Pointer to the TCP_CB to be flushed.
**/
VOID
TcpFlushPcb (
IN OUT TCP_CB *Tcb
)
{
SOCKET *Sock;
TCP_PROTO_DATA *TcpProto;
IpIoConfigIp (Tcb->IpInfo, NULL);
Sock = Tcb->Sk;
TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
if (SOCK_IS_CONFIGURED (Sock)) {
RemoveEntryList (&Tcb->List);
if (Sock->DevicePath != NULL) {
//
// Uninstall the device path protocl.
//
gBS->UninstallProtocolInterface (
Sock->SockHandle,
&gEfiDevicePathProtocolGuid,
Sock->DevicePath
);
FreePool (Sock->DevicePath);
Sock->DevicePath = NULL;
}
TcpSetVariableData (TcpProto->TcpService);
}
NetbufFreeList (&Tcb->SndQue);
NetbufFreeList (&Tcb->RcvQue);
Tcb->State = TCP_CLOSED;
}
/**
Attach a Pcb to the socket.
@param[in] Sk Pointer to the socket of this TCP instance.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_OUT_OF_RESOURCES Failed due to resource limits.
**/
EFI_STATUS
TcpAttachPcb (
IN SOCKET *Sk
)
{
TCP_CB *Tcb;
TCP_PROTO_DATA *ProtoData;
IP_IO *IpIo;
Tcb = AllocateZeroPool (sizeof (TCP_CB));
if (Tcb == NULL) {
DEBUG ((EFI_D_ERROR, "TcpConfigurePcb: failed to allocate a TCB\n"));
return EFI_OUT_OF_RESOURCES;
}
ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
IpIo = ProtoData->TcpService->IpIo;
//
// Create an IpInfo for this Tcb.
//
Tcb->IpInfo = IpIoAddIp (IpIo);
if (Tcb->IpInfo == NULL) {
FreePool (Tcb);
return EFI_OUT_OF_RESOURCES;
}
InitializeListHead (&Tcb->List);
InitializeListHead (&Tcb->SndQue);
InitializeListHead (&Tcb->RcvQue);
Tcb->State = TCP_CLOSED;
Tcb->Sk = Sk;
ProtoData->TcpPcb = Tcb;
return EFI_SUCCESS;
}
/**
Detach the Pcb of the socket.
@param[in, out] Sk Pointer to the socket of this TCP instance.
**/
VOID
TcpDetachPcb (
IN OUT SOCKET *Sk
)
{
TCP_PROTO_DATA *ProtoData;
TCP_CB *Tcb;
ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
Tcb = ProtoData->TcpPcb;
ASSERT (Tcb != NULL);
TcpFlushPcb (Tcb);
IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
FreePool (Tcb);
ProtoData->TcpPcb = NULL;
}
/**
Configure the Pcb using CfgData.
@param[in] Sk Pointer to the socket of this TCP instance.
@param[in] CfgData Pointer to the TCP configuration data.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER A same access point has been configured in
another TCP instance.
@retval EFI_OUT_OF_RESOURCES Failed due to resource limits.
**/
EFI_STATUS
TcpConfigurePcb (
IN SOCKET *Sk,
IN TCP_CONFIG_DATA *CfgData
)
{
IP_IO_IP_CONFIG_DATA IpCfgData;
EFI_STATUS Status;
EFI_TCP4_OPTION *Option;
TCP_PROTO_DATA *TcpProto;
TCP_CB *Tcb;
TCP_ACCESS_POINT *TcpAp;
ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved;
Tcb = TcpProto->TcpPcb;
ASSERT (Tcb != NULL);
if (Sk->IpVersion == IP_VERSION_4) {
//
// Add Ip for send pkt to the peer
//
CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
IpCfgData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
IpCfgData.Ip4CfgData.TypeOfService = CfgData->Tcp4CfgData.TypeOfService;
IpCfgData.Ip4CfgData.TimeToLive = CfgData->Tcp4CfgData.TimeToLive;
IpCfgData.Ip4CfgData.UseDefaultAddress = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
IpCfgData.Ip4CfgData.SubnetMask = CfgData->Tcp4CfgData.AccessPoint.SubnetMask;
IpCfgData.Ip4CfgData.ReceiveTimeout = (UINT32) (-1);
CopyMem (
&IpCfgData.Ip4CfgData.StationAddress,
&CfgData->Tcp4CfgData.AccessPoint.StationAddress,
sizeof (EFI_IPv4_ADDRESS)
);
} else {
ASSERT (Sk->IpVersion == IP_VERSION_6);
CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA));
IpCfgData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
IpCfgData.Ip6CfgData.TrafficClass = CfgData->Tcp6CfgData.TrafficClass;
IpCfgData.Ip6CfgData.HopLimit = CfgData->Tcp6CfgData.HopLimit;
IpCfgData.Ip6CfgData.ReceiveTimeout = (UINT32) (-1);
IP6_COPY_ADDRESS (
&IpCfgData.Ip6CfgData.StationAddress,
&CfgData->Tcp6CfgData.AccessPoint.StationAddress
);
IP6_COPY_ADDRESS (
&IpCfgData.Ip6CfgData.DestinationAddress,
&CfgData->Tcp6CfgData.AccessPoint.RemoteAddress
);
}
//
// Configure the IP instance this Tcb consumes.
//
Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
if (EFI_ERROR (Status)) {
goto OnExit;
}
if (Sk->IpVersion == IP_VERSION_4) {
//
// Get the default address information if the instance is configured to use default address.
//
CfgData->Tcp4CfgData.AccessPoint.StationAddress = IpCfgData.Ip4CfgData.StationAddress;
CfgData->Tcp4CfgData.AccessPoint.SubnetMask = IpCfgData.Ip4CfgData.SubnetMask;
TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint;
} else {
IP6_COPY_ADDRESS (
&CfgData->Tcp6CfgData.AccessPoint.StationAddress,
&IpCfgData.Ip6CfgData.StationAddress
);
TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint;
}
//
// check if we can bind this endpoint in CfgData
//
Status = TcpBind (TcpAp, Sk->IpVersion);
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"TcpConfigurePcb: Bind endpoint failed with %r\n",
Status)
);
goto OnExit;
}
//
// Initalize the operating information in this Tcb
//
ASSERT (Tcb->State == TCP_CLOSED &&
IsListEmpty (&Tcb->SndQue) &&
IsListEmpty (&Tcb->RcvQue));
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
Tcb->State = TCP_CLOSED;
Tcb->SndMss = 536;
Tcb->RcvMss = TcpGetRcvMss (Sk);
Tcb->SRtt = 0;
Tcb->Rto = 3 * TCP_TICK_HZ;
Tcb->CWnd = Tcb->SndMss;
Tcb->Ssthresh = 0xffffffff;
Tcb->CongestState = TCP_CONGEST_OPEN;
Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN;
Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD;
Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE;
Tcb->MaxRexmit = TCP_MAX_LOSS;
Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME;
Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME;
Tcb->ConnectTimeout = TCP_CONNECT_TIME;
if (Sk->IpVersion == IP_VERSION_4) {
//
// initialize Tcb in the light of CfgData
//
Tcb->Ttl = CfgData->Tcp4CfgData.TimeToLive;
Tcb->Tos = CfgData->Tcp4CfgData.TypeOfService;
Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR));
Tcb->LocalEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort);
Tcb->SubnetMask = CfgData->Tcp4CfgData.AccessPoint.SubnetMask;
CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort);
Option = CfgData->Tcp4CfgData.ControlOption;
} else {
Tcb->Ttl = CfgData->Tcp6CfgData.HopLimit;
Tcb->Tos = CfgData->Tcp6CfgData.TrafficClass;
IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress);
Tcb->LocalEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort);
IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress);
Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort);
//
// Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same.
//
Option = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption;
}
if (Option != NULL) {
SET_RCV_BUFFSIZE (
Sk,
(UINT32) (TCP_COMP_VAL (
TCP_RCV_BUF_SIZE_MIN,
TCP_RCV_BUF_SIZE,
TCP_RCV_BUF_SIZE,
Option->ReceiveBufferSize
)
)
);
SET_SND_BUFFSIZE (
Sk,
(UINT32) (TCP_COMP_VAL (
TCP_SND_BUF_SIZE_MIN,
TCP_SND_BUF_SIZE,
TCP_SND_BUF_SIZE,
Option->SendBufferSize
)
)
);
SET_BACKLOG (
Sk,
(UINT32) (TCP_COMP_VAL (
TCP_BACKLOG_MIN,
TCP_BACKLOG,
TCP_BACKLOG,
Option->MaxSynBackLog
)
)
);
Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
TCP_MAX_LOSS_MIN,
TCP_MAX_LOSS,
TCP_MAX_LOSS,
Option->DataRetries
);
Tcb->FinWait2Timeout = TCP_COMP_VAL (
TCP_FIN_WAIT2_TIME,
TCP_FIN_WAIT2_TIME_MAX,
TCP_FIN_WAIT2_TIME,
(UINT32) (Option->FinTimeout * TCP_TICK_HZ)
);
if (Option->TimeWaitTimeout != 0) {
Tcb->TimeWaitTimeout = TCP_COMP_VAL (
TCP_TIME_WAIT_TIME,
TCP_TIME_WAIT_TIME_MAX,
TCP_TIME_WAIT_TIME,
(UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
);
} else {
Tcb->TimeWaitTimeout = 0;
}
if (Option->KeepAliveProbes != 0) {
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
TCP_MAX_KEEPALIVE_MIN,
TCP_MAX_KEEPALIVE,
TCP_MAX_KEEPALIVE,
Option->KeepAliveProbes
);
Tcb->KeepAliveIdle = TCP_COMP_VAL (
TCP_KEEPALIVE_IDLE_MIN,
TCP_KEEPALIVE_IDLE_MAX,
TCP_KEEPALIVE_IDLE_MIN,
(UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
);
Tcb->KeepAlivePeriod = TCP_COMP_VAL (
TCP_KEEPALIVE_PERIOD_MIN,
TCP_KEEPALIVE_PERIOD,
TCP_KEEPALIVE_PERIOD,
(UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
);
}
Tcb->ConnectTimeout = TCP_COMP_VAL (
TCP_CONNECT_TIME_MIN,
TCP_CONNECT_TIME,
TCP_CONNECT_TIME,
(UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
);
if (!Option->EnableNagle) {
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
}
if (!Option->EnableTimeStamp) {
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
}
if (!Option->EnableWindowScaling) {
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
}
}
//
// The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
// determined, construct the IP device path and install it.
//
Status = TcpInstallDevicePath (Sk);
if (EFI_ERROR (Status)) {
goto OnExit;
}
//
// update state of Tcb and socket
//
if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) ||
((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag)
) {
TcpSetState (Tcb, TCP_LISTEN);
SockSetState (Sk, SO_LISTENING);
Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
} else {
Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
}
if (Sk->IpVersion == IP_VERSION_6) {
Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;
}
TcpInsertTcb (Tcb);
OnExit:
return Status;
}
/**
The procotol handler provided to the socket layer, which is used to
dispatch the socket level requests by calling the corresponding
TCP layer functions.
@param[in] Sock Pointer to the socket of this TCP instance.
@param[in] Request The code of this operation request.
@param[in] Data Pointer to the operation specific data passed in
together with the operation request. This is an
optional parameter that may be NULL.
@retval EFI_SUCCESS The socket request completed successfully.
@retval other The error status returned by the corresponding TCP
layer function.
**/
EFI_STATUS
TcpDispatcher (
IN SOCKET *Sock,
IN UINT8 Request,
IN VOID *Data OPTIONAL
)
{
TCP_CB *Tcb;
TCP_PROTO_DATA *ProtoData;
ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;
Tcb = ProtoData->TcpPcb;
switch (Request) {
case SOCK_POLL:
if (Tcb->Sk->IpVersion == IP_VERSION_4) {
ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4);
} else {
ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6);
}
break;
case SOCK_CONSUMED:
//
// After user received data from socket buffer, socket will
// notify TCP using this message to give it a chance to send out
// window update information
//
ASSERT (Tcb != NULL);
TcpOnAppConsume (Tcb);
break;
case SOCK_SND:
ASSERT (Tcb != NULL);
TcpOnAppSend (Tcb);
break;
case SOCK_CLOSE:
TcpOnAppClose (Tcb);
break;
case SOCK_ABORT:
TcpOnAppAbort (Tcb);
break;
case SOCK_SNDPUSH:
Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
break;
case SOCK_SNDURG:
Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
break;
case SOCK_CONNECT:
TcpOnAppConnect (Tcb);
break;
case SOCK_ATTACH:
return TcpAttachPcb (Sock);
break;
case SOCK_FLUSH:
TcpFlushPcb (Tcb);
break;
case SOCK_DETACH:
TcpDetachPcb (Sock);
break;
case SOCK_CONFIGURE:
return TcpConfigurePcb (
Sock,
(TCP_CONFIG_DATA *) Data
);
break;
case SOCK_MODE:
ASSERT ((Data != NULL) && (Tcb != NULL));
if (Tcb->Sk->IpVersion == IP_VERSION_4) {
return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
} else {
return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data);
}
break;
case SOCK_ROUTE:
ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4));
return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
default:
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,891 @@
/** @file
The driver binding and service binding protocol for the TCP driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
UINT16 mTcp4RandomPort;
UINT16 mTcp6RandomPort;
TCP_HEARTBEAT_TIMER mTcpTimer = {
NULL,
0
};
EFI_TCP4_PROTOCOL gTcp4ProtocolTemplate = {
Tcp4GetModeData,
Tcp4Configure,
Tcp4Routes,
Tcp4Connect,
Tcp4Accept,
Tcp4Transmit,
Tcp4Receive,
Tcp4Close,
Tcp4Cancel,
Tcp4Poll
};
EFI_TCP6_PROTOCOL gTcp6ProtocolTemplate = {
Tcp6GetModeData,
Tcp6Configure,
Tcp6Connect,
Tcp6Accept,
Tcp6Transmit,
Tcp6Receive,
Tcp6Close,
Tcp6Cancel,
Tcp6Poll
};
SOCK_INIT_DATA mTcpDefaultSockData = {
SockStream,
SO_CLOSED,
NULL,
TCP_BACKLOG,
TCP_SND_BUF_SIZE,
TCP_RCV_BUF_SIZE,
IP_VERSION_4,
NULL,
TcpCreateSocketCallback,
TcpDestroySocketCallback,
NULL,
NULL,
0,
TcpDispatcher,
NULL,
};
EFI_DRIVER_BINDING_PROTOCOL gTcpDriverBinding = {
TcpDriverBindingSupported,
TcpDriverBindingStart,
TcpDriverBindingStop,
0xa,
NULL,
NULL
};
EFI_SERVICE_BINDING_PROTOCOL gTcpServiceBinding = {
TcpServiceBindingCreateChild,
TcpServiceBindingDestroyChild
};
/**
Create and start the heartbeat timer for the TCP driver.
@retval EFI_SUCCESS The timer was successfully created and started.
@retval other The timer was not created.
**/
EFI_STATUS
TcpCreateTimer (
VOID
)
{
EFI_STATUS Status;
Status = EFI_SUCCESS;
if (mTcpTimer.RefCnt == 0) {
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
TcpTicking,
NULL,
&mTcpTimer.TimerEvent
);
if (!EFI_ERROR (Status)) {
Status = gBS->SetTimer (
mTcpTimer.TimerEvent,
TimerPeriodic,
(UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
);
}
}
if (!EFI_ERROR (Status)) {
mTcpTimer.RefCnt++;
}
return Status;
}
/**
Stop and destroy the heartbeat timer for TCP driver.
**/
VOID
TcpDestroyTimer (
VOID
)
{
ASSERT (mTcpTimer.RefCnt > 0);
mTcpTimer.RefCnt--;
if (mTcpTimer.RefCnt > 0) {
return;
}
gBS->SetTimer (mTcpTimer.TimerEvent, TimerCancel, 0);
gBS->CloseEvent (mTcpTimer.TimerEvent);
mTcpTimer.TimerEvent = NULL;
}
/**
The entry point for Tcp driver, which is used to install Tcp driver on the ImageHandle.
@param[in] ImageHandle The firmware allocated handle for this driver image.
@param[in] SystemTable Pointer to the EFI system table.
@retval EFI_SUCCESS The driver loaded.
@retval other The driver did not load.
**/
EFI_STATUS
EFIAPI
TcpDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT32 Seed;
//
// Install the TCP Driver Binding Protocol
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gTcpDriverBinding,
ImageHandle,
&gTcpComponentName,
&gTcpComponentName2
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Initialize ISS and random port.
//
Seed = NetRandomInitSeed ();
mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss;
mTcp4RandomPort = (UINT16) (TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN));
mTcp6RandomPort = mTcp4RandomPort;
return EFI_SUCCESS;
}
/**
Create a new TCP4 or TCP6 driver service binding protocol
@param[in] Controller Controller handle of device to bind driver to.
@param[in] ImageHandle The TCP driver's image handle.
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
@retval EFI_SUCCESS A new IP6 service binding private was created.
**/
EFI_STATUS
TcpCreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE Image,
IN UINT8 IpVersion
)
{
EFI_STATUS Status;
EFI_GUID *IpServiceBindingGuid;
EFI_GUID *TcpServiceBindingGuid;
TCP_SERVICE_DATA *TcpServiceData;
IP_IO_OPEN_DATA OpenData;
if (IpVersion == IP_VERSION_4) {
IpServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
} else {
IpServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
}
Status = gBS->OpenProtocol (
Controller,
TcpServiceBindingGuid,
NULL,
Image,
Controller,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
return EFI_ALREADY_STARTED;
}
Status = gBS->OpenProtocol (
Controller,
IpServiceBindingGuid,
NULL,
Image,
Controller,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
//
// Create the TCP service data.
//
TcpServiceData = AllocateZeroPool (sizeof (TCP_SERVICE_DATA));
if (TcpServiceData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
TcpServiceData->Signature = TCP_DRIVER_SIGNATURE;
TcpServiceData->ControllerHandle = Controller;
TcpServiceData->DriverBindingHandle = Image;
TcpServiceData->IpVersion = IpVersion;
CopyMem (
&TcpServiceData->ServiceBinding,
&gTcpServiceBinding,
sizeof (EFI_SERVICE_BINDING_PROTOCOL)
);
TcpServiceData->IpIo = IpIoCreate (Image, Controller, IpVersion);
if (TcpServiceData->IpIo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
InitializeListHead (&TcpServiceData->SocketList);
ZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));
if (IpVersion == IP_VERSION_4) {
CopyMem (
&OpenData.IpConfigData.Ip4CfgData,
&mIp4IoDefaultIpConfigData,
sizeof (EFI_IP4_CONFIG_DATA)
);
OpenData.IpConfigData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
} else {
CopyMem (
&OpenData.IpConfigData.Ip6CfgData,
&mIp6IoDefaultIpConfigData,
sizeof (EFI_IP6_CONFIG_DATA)
);
OpenData.IpConfigData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
}
OpenData.PktRcvdNotify = TcpRxCallback;
Status = IpIoOpen (TcpServiceData->IpIo, &OpenData);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = TcpCreateTimer ();
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
TcpServiceBindingGuid,
&TcpServiceData->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
TcpDestroyTimer ();
goto ON_ERROR;
}
TcpSetVariableData (TcpServiceData);
return EFI_SUCCESS;
ON_ERROR:
if (TcpServiceData->IpIo != NULL) {
IpIoDestroy (TcpServiceData->IpIo);
}
FreePool (TcpServiceData);
return Status;
}
/**
Destroy a TCP6 or TCP4 service binding instance. It will release all
the resources allocated by the instance.
@param[in] Controller Controller handle of device to bind driver to.
@param[in] ImageHandle The TCP driver's image handle.
@param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6
@retval EFI_SUCCESS The resources used by the instance were cleaned up.
@retval Others Failed to clean up some of the resources.
**/
EFI_STATUS
TcpDestroyService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
IN UINTN NumberOfChildren,
IN UINT8 IpVersion
)
{
EFI_HANDLE NicHandle;
EFI_GUID *IpProtocolGuid;
EFI_GUID *ServiceBindingGuid;
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
TCP_SERVICE_DATA *TcpServiceData;
EFI_STATUS Status;
SOCKET *Sock;
ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
if (IpVersion == IP_VERSION_4) {
IpProtocolGuid = &gEfiIp4ProtocolGuid;
ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
} else {
IpProtocolGuid = &gEfiIp6ProtocolGuid;
ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
}
NicHandle = NetLibGetNicHandle (Controller, IpProtocolGuid);
if (NicHandle == NULL) {
return EFI_NOT_FOUND;
}
Status = gBS->OpenProtocol (
NicHandle,
ServiceBindingGuid,
(VOID **) &ServiceBinding,
ImageHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
TcpServiceData = TCP_SERVICE_FROM_THIS (ServiceBinding);
if (NumberOfChildren == 0) {
//
// Uninstall TCP servicebinding protocol
//
gBS->UninstallMultipleProtocolInterfaces (
NicHandle,
ServiceBindingGuid,
ServiceBinding,
NULL
);
//
// Destroy the IpIO consumed by TCP driver
//
IpIoDestroy (TcpServiceData->IpIo);
//
// Destroy the heartbeat timer.
//
TcpDestroyTimer ();
//
// Clear the variable.
//
TcpClearVariableData (TcpServiceData);
//
// Release the TCP service data
//
FreePool (TcpServiceData);
} else {
while (!IsListEmpty (&TcpServiceData->SocketList)) {
Sock = NET_LIST_HEAD (&TcpServiceData->SocketList, SOCKET, Link);
ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
}
}
return EFI_SUCCESS;
}
/**
Test to see if this driver supports ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to test.
@param[in] RemainingDevicePath Optional parameter use to pick a specific
child device to start.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_ALREADY_STARTED This driver is already running on this device.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
BOOLEAN IsTcp4Started;
//
// Test for the Tcp4ServiceBinding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiTcp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
//
// Test for the Ip4ServiceBinding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
IsTcp4Started = FALSE;
} else {
IsTcp4Started = TRUE;
}
//
// Check the Tcp6ServiceBinding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiTcp6ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
//
// Test for the Ip6ServiceBinding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp6ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
} else if (IsTcp4Started) {
return EFI_ALREADY_STARTED;
}
return EFI_UNSUPPORTED;
}
/**
Start this driver on ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to.
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS The driver is added to ControllerHandle.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to start the
driver.
@retval other The driver cannot be added to ControllerHandle.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Tcp4Status;
EFI_STATUS Tcp6Status;
Tcp4Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4);
if ((Tcp4Status == EFI_ALREADY_STARTED) || (Tcp4Status == EFI_UNSUPPORTED)) {
Tcp4Status = EFI_SUCCESS;
}
Tcp6Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6);
if ((Tcp6Status == EFI_ALREADY_STARTED) || (Tcp6Status == EFI_UNSUPPORTED)) {
Tcp6Status = EFI_SUCCESS;
}
if (!EFI_ERROR (Tcp4Status) || !EFI_ERROR (Tcp6Status)) {
return EFI_SUCCESS;
} else if (EFI_ERROR (Tcp4Status)) {
return Tcp4Status;
} else {
return Tcp6Status;
}
}
/**
Stop this driver on ControllerHandle.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
EFI_STATUS Tcp4Status;
EFI_STATUS Tcp6Status;
Tcp4Status = TcpDestroyService (
ControllerHandle,
This->DriverBindingHandle,
NumberOfChildren,
IP_VERSION_4
);
Tcp6Status = TcpDestroyService (
ControllerHandle,
This->DriverBindingHandle,
NumberOfChildren,
IP_VERSION_6
);
if (EFI_ERROR (Tcp4Status) && EFI_ERROR (Tcp6Status)) {
return EFI_DEVICE_ERROR;
} else {
return EFI_SUCCESS;
}
}
/**
The Callback funtion called after the TCP socket was created.
@param[in] This Pointer to the socket just created
@param[in] Context Context of the socket
@retval EFI_SUCCESS This protocol installed successfully.
@retval other An error occured.
**/
EFI_STATUS
TcpCreateSocketCallback (
IN SOCKET *This,
IN VOID *Context
)
{
EFI_STATUS Status;
TCP_SERVICE_DATA *TcpServiceData;
EFI_GUID *IpProtocolGuid;
VOID *Ip;
if (This->IpVersion == IP_VERSION_4) {
IpProtocolGuid = &gEfiIp4ProtocolGuid;
} else {
IpProtocolGuid = &gEfiIp6ProtocolGuid;
}
TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
//
// Open the default IP protocol of IP_IO BY_DRIVER.
//
Status = gBS->OpenProtocol (
TcpServiceData->IpIo->ChildHandle,
IpProtocolGuid,
&Ip,
TcpServiceData->DriverBindingHandle,
This->SockHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the device path on the handle where service binding resides on.
//
Status = gBS->OpenProtocol (
TcpServiceData->ControllerHandle,
&gEfiDevicePathProtocolGuid,
(VOID **) &This->ParentDevicePath,
TcpServiceData->DriverBindingHandle,
This->SockHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
TcpServiceData->IpIo->ChildHandle,
IpProtocolGuid,
TcpServiceData->DriverBindingHandle,
This->SockHandle
);
} else {
//
// Insert this socket into the SocketList.
//
InsertTailList (&TcpServiceData->SocketList, &This->Link);
}
return Status;
}
/**
The callback function called before the TCP socket was to be destroyed.
@param[in] This The TCP socket to be destroyed.
@param[in] Context The context of the socket.
**/
VOID
TcpDestroySocketCallback (
IN SOCKET *This,
IN VOID *Context
)
{
TCP_SERVICE_DATA *TcpServiceData;
EFI_GUID *IpProtocolGuid;
if (This->IpVersion == IP_VERSION_4) {
IpProtocolGuid = &gEfiIp4ProtocolGuid;
} else {
IpProtocolGuid = &gEfiIp6ProtocolGuid;
}
TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
//
// Remove this node from the list.
//
RemoveEntryList (&This->Link);
//
// Close the device path protocol
//
gBS->CloseProtocol (
TcpServiceData->ControllerHandle,
&gEfiDevicePathProtocolGuid,
TcpServiceData->DriverBindingHandle,
This->SockHandle
);
//
// Close the IP protocol.
//
gBS->CloseProtocol (
TcpServiceData->IpIo->ChildHandle,
IpProtocolGuid,
TcpServiceData->DriverBindingHandle,
This->SockHandle
);
}
/**
Creates a child handle with a set of TCP services.
The CreateChild() function installs a protocol on ChildHandle.
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
@param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param[in, out] ChildHandle Pointer to the handle of the child to create.
If it is NULL, then a new handle is created.
If it is a pointer to an existing UEFI handle,
then the protocol is added to the existing UEFI handle.
@retval EFI_SUCCES The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child.
@retval other The child handle was not created.
**/
EFI_STATUS
EFIAPI
TcpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
SOCKET *Sock;
TCP_SERVICE_DATA *TcpServiceData;
TCP_PROTO_DATA TcpProto;
EFI_STATUS Status;
EFI_TPL OldTpl;
if (NULL == This || NULL == ChildHandle) {
return EFI_INVALID_PARAMETER;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
Status = EFI_SUCCESS;
TcpServiceData = TCP_SERVICE_FROM_THIS (This);
TcpProto.TcpService = TcpServiceData;
TcpProto.TcpPcb = NULL;
//
// Create a tcp instance with defualt Tcp default
// sock init data and TcpProto
//
mTcpDefaultSockData.ProtoData = &TcpProto;
mTcpDefaultSockData.DataSize = sizeof (TCP_PROTO_DATA);
mTcpDefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
mTcpDefaultSockData.IpVersion = TcpServiceData->IpVersion;
if (TcpServiceData->IpVersion == IP_VERSION_4) {
mTcpDefaultSockData.Protocol = &gTcp4ProtocolTemplate;
} else {
mTcpDefaultSockData.Protocol = &gTcp6ProtocolTemplate;
}
Sock = SockCreateChild (&mTcpDefaultSockData);
if (NULL == Sock) {
DEBUG (
(EFI_D_ERROR,
"TcpDriverBindingCreateChild: No resource to create a Tcp Child\n")
);
Status = EFI_OUT_OF_RESOURCES;
} else {
*ChildHandle = Sock->SockHandle;
}
mTcpDefaultSockData.ProtoData = NULL;
gBS->RestoreTPL (OldTpl);
return Status;
}
/**
Destroys a child handle with a set of TCP services.
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
that was installed by CreateChild() from ChildHandle. If the removed protocol is the
last protocol on ChildHandle, then ChildHandle is destroyed.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Handle of the child to be destroyed.
@retval EFI_SUCCES The protocol was removed from ChildHandle.
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
@retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
because its services are being used.
@retval other The child handle was not destroyed.
**/
EFI_STATUS
EFIAPI
TcpServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
VOID *Tcp;
SOCKET *Sock;
EFI_TPL OldTpl;
if (NULL == This || NULL == ChildHandle) {
return EFI_INVALID_PARAMETER;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// retrieve the Tcp4 protocol from ChildHandle
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiTcp4ProtocolGuid,
&Tcp,
gTcpDriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
//
// No Tcp4, try the Tcp6 protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiTcp6ProtocolGuid,
&Tcp,
gTcpDriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
Status = EFI_UNSUPPORTED;
}
}
if (!EFI_ERROR (Status)) {
//
// destroy this sock and related Tcp protocol control
// block
//
Sock = SOCK_FROM_THIS (Tcp);
SockDestroyChild (Sock);
}
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,230 @@
/** @file
The prototype of driver binding and service binding protocol for TCP driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _TCP_DRIVER_H_
#define _TCP_DRIVER_H_
#define TCP_DRIVER_SIGNATURE SIGNATURE_32 ('T', 'C', 'P', 'D')
#define TCP_PORT_KNOWN 1024
#define TCP_PORT_USER_RESERVED 65535
typedef struct _TCP_HEARTBEAT_TIMER {
EFI_EVENT TimerEvent;
INTN RefCnt;
} TCP_HEARTBEAT_TIMER;
typedef struct _TCP_SERVICE_DATA {
UINT32 Signature;
EFI_HANDLE ControllerHandle;
EFI_HANDLE DriverBindingHandle;
UINT8 IpVersion;
IP_IO *IpIo;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
CHAR16 *MacString;
LIST_ENTRY SocketList;
} TCP_SERVICE_DATA;
typedef struct _TCP_PROTO_DATA {
TCP_SERVICE_DATA *TcpService;
TCP_CB *TcpPcb;
} TCP_PROTO_DATA;
#define TCP_SERVICE_FROM_THIS(a) \
CR ( \
(a), \
TCP_SERVICE_DATA, \
ServiceBinding, \
TCP_DRIVER_SIGNATURE \
)
//
// Function prototype for the driver's entry point
//
/**
The entry point for Tcp driver, used to install Tcp driver on the ImageHandle.
@param[in] ImageHandle The firmware allocated handle for this driver image.
@param[in] SystemTable Pointer to the EFI system table.
@retval EFI_SUCCESS The driver loaded.
@retval other The driver did not load.
**/
EFI_STATUS
EFIAPI
TcpDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
//
// Function prototypes for the Driver Binding Protocol
//
/**
Test to see if this driver supports ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of the device to test.
@param[in] RemainingDevicePath Optional parameter use to pick a specific
child device to start.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_ALREADY_STARTED This driver is already running on this device.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Start this driver on ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to.
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS The driver was added to ControllerHandle.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to start the
driver.
@retval other The driver cannot be added to ControllerHandle.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Stop this driver on ControllerHandle.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
);
/**
The Callback funtion called after the TCP socket is created.
@param[in] This Pointer to the socket just created.
@param[in] Context The context of the socket.
@retval EFI_SUCCESS This protocol is installed successfully.
@retval other An error occured.
**/
EFI_STATUS
TcpCreateSocketCallback (
IN SOCKET *This,
IN VOID *Context
);
/**
The callback function called before the TCP socket is to be destroyed.
@param[in] This The TCP socket to be destroyed.
@param[in] Context The context of the socket.
**/
VOID
TcpDestroySocketCallback (
IN SOCKET *This,
IN VOID *Context
);
//
// Function ptototypes for the ServiceBinding Prococol
//
/**
Creates a child handle with a set of TCP services.
The CreateChild() function installs a protocol on ChildHandle.
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
@param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param[in, out] ChildHandle Pointer to the handle of the child to create.
If it is NULL, then a new handle is created.
If it is a pointer to an existing UEFI handle,
then the protocol is added to the existing UEFI handle.
@retval EFI_SUCCES The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child.
@retval other The child handle was not created.
**/
EFI_STATUS
EFIAPI
TcpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
);
/**
Destroys a child handle with a set of TCP services.
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
that was installed by CreateChild() from ChildHandle. If the removed protocol is the
last protocol on ChildHandle, then ChildHandle is destroyed.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Handle of the child to destroy.
@retval EFI_SUCCES The protocol was removed from ChildHandle.
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
@retval EFI_INVALID_PARAMETER The child handle is not a valid UEFI Handle.
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
because its services are being used.
@retval other The child handle was not destroyed.
**/
EFI_STATUS
EFIAPI
TcpServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
#endif

View File

@@ -0,0 +1,83 @@
## @file TcpDxe.inf
# Component description file for Tcp module.
#
# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = TcpDxe
FILE_GUID = 1A7E4468-2F55-4a56-903C-01265EB7622B
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = TcpDriverEntryPoint
UNLOAD_IMAGE = NetLibDefaultUnload
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
TcpDriver.c
SockImpl.c
SockInterface.c
TcpDispatcher.c
TcpOutput.c
TcpMain.c
SockImpl.h
TcpMisc.c
TcpProto.h
TcpOption.c
TcpInput.c
TcpFunc.h
TcpOption.h
TcpTimer.c
TcpMain.h
Socket.h
ComponentName.c
TcpIo.c
TcpDriver.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DevicePathLib
DebugLib
MemoryAllocationLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
DpcLib
NetLib
IpIoLib
[Protocols]
gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiTcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiTcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiTcp6ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiTcp6ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED

724
NetworkPkg/TcpDxe/TcpFunc.h Normal file
View File

@@ -0,0 +1,724 @@
/** @file
Declaration of external functions shared in TCP driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _TCP_FUNC_H_
#define _TCP_FUNC_H_
#include "TcpOption.h"
#define TCP_COMP_VAL(Min, Max, Default, Val) \
((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
/**
Timeout handler prototype.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
typedef
VOID
(*TCP_TIMER_HANDLER) (
IN OUT TCP_CB *Tcb
);
//
// Functions in TcpMisc.c
//
/**
Initialize the Tcb locally related members.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpInitTcbLocal (
IN OUT TCP_CB *Tcb
);
/**
Initialize the peer related members.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Seg Pointer to the segment that contains the peer's intial information.
@param[in] Opt Pointer to the options announced by the peer.
**/
VOID
TcpInitTcbPeer (
IN OUT TCP_CB *Tcb,
IN TCP_SEG *Seg,
IN TCP_OPTION *Opt
);
/**
Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
@param[in] Addr Pointer to the IP address needs to match.
@param[in] Port The port number needs to match.
@param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack.
IP_VERSION_6 indicates TCP is running on IP6 stack.
@retval TRUE The Tcb which matches the <Addr Port> pairs exists.
@retval FALSE Otherwise
**/
BOOLEAN
TcpFindTcbByPeer (
IN EFI_IP_ADDRESS *Addr,
IN TCP_PORTNO Port,
IN UINT8 Version
);
/**
Locate the TCP_CB related to the socket pair.
@param[in] LocalPort The local port number.
@param[in] LocalIp The local IP address.
@param[in] RemotePort The remote port number.
@param[in] RemoteIp The remote IP address.
@param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
IP_VERSION_6 indicates TCP is running on IP6 stack.
@param[in] Syn If TRUE, the listen sockets are searched.
@return Pointer to the related TCP_CB. If NULL, no match is found.
**/
TCP_CB *
TcpLocateTcb (
IN TCP_PORTNO LocalPort,
IN EFI_IP_ADDRESS *LocalIp,
IN TCP_PORTNO RemotePort,
IN EFI_IP_ADDRESS *RemoteIp,
IN UINT8 Version,
IN BOOLEAN Syn
);
/**
Insert a Tcb into the proper queue.
@param[in] Tcb Pointer to the TCP_CB to be inserted.
@retval 0 The Tcb was inserted successfully.
@retval -1 An error condition occurred.
**/
INTN
TcpInsertTcb (
IN TCP_CB *Tcb
);
/**
Clone a TCP_CB from Tcb.
@param[in] Tcb Pointer to the TCP_CB to be cloned.
@return Pointer to the new cloned TCP_CB. If NULL, an error condition occurred.
**/
TCP_CB *
TcpCloneTcb (
IN TCP_CB *Tcb
);
/**
Compute an ISS to be used by a new connection.
@return The result ISS.
**/
TCP_SEQNO
TcpGetIss (
VOID
);
/**
Get the local mss.
@param[in] Sock Pointer to the socket to get mss.
@return The mss size.
**/
UINT16
TcpGetRcvMss (
IN SOCKET *Sock
);
/**
Set the Tcb's state.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] State The state to be set.
**/
VOID
TcpSetState (
IN TCP_CB *Tcb,
IN UINT8 State
);
/**
Compute the TCP segment's checksum.
@param[in] Nbuf Pointer to the buffer that contains the TCP segment.
@param[in] HeadSum The checksum value of the fixed part of pseudo header.
@return The checksum value.
**/
UINT16
TcpChecksum (
IN NET_BUF *Nbuf,
IN UINT16 HeadSum
);
/**
Translate the information from the head of the received TCP
segment Nbuf contains, and fill it into a TCP_SEG structure.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in, out] Nbuf Pointer to the buffer contains the TCP segment.
@return Pointer to the TCP_SEG that contains the translated TCP head information.
**/
TCP_SEG *
TcpFormatNetbuf (
IN TCP_CB *Tcb,
IN OUT NET_BUF *Nbuf
);
/**
Initialize an active connection,
@param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a
connection.
**/
VOID
TcpOnAppConnect (
IN OUT TCP_CB *Tcb
);
/**
Application has consumed some data, check whether
to send a window update ack or a delayed ack.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpOnAppConsume (
IN TCP_CB *Tcb
);
/**
Initiate the connection close procedure, called when
applications want to close the connection.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpOnAppClose (
IN OUT TCP_CB *Tcb
);
/**
Check whether the application's newly delivered data can be sent out.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@retval 0 The data has been sent out successfully.
@retval -1 The Tcb is not in a state that data is permitted to
be sent out.
**/
INTN
TcpOnAppSend (
IN OUT TCP_CB *Tcb
);
/**
Abort the connection by sending a reset segment: called
when the application wants to abort the connection.
@param[in] Tcb Pointer to the TCP_CB of the TCP instance.
**/
VOID
TcpOnAppAbort (
IN TCP_CB *Tcb
);
/**
Reset the connection related with Tcb.
@param[in] Tcb Pointer to the TCP_CB of the connection to be reset.
**/
VOID
TcpResetConnection (
IN TCP_CB *Tcb
);
/**
Set the Tcp variable data.
@param[in] TcpService Tcp service data.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
@retval other Set variable failed.
**/
EFI_STATUS
TcpSetVariableData (
IN TCP_SERVICE_DATA *TcpService
);
/**
Clear the variable and free the resource.
@param[in] TcpService Tcp service data.
**/
VOID
TcpClearVariableData (
IN TCP_SERVICE_DATA *TcpService
);
/**
Install the device path protocol on the TCP instance.
@param[in] Sock Pointer to the socket representing the TCP instance.
@retval EFI_SUCCESS The device path protocol installed.
@retval other Failed to install the device path protocol.
**/
EFI_STATUS
TcpInstallDevicePath (
IN SOCKET *Sock
);
//
// Functions in TcpOutput.c
//
/**
Compute the sequence space left in the old receive window.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@return The sequence space left in the old receive window.
**/
UINT32
TcpRcvWinOld (
IN TCP_CB *Tcb
);
/**
Compute the current receive window.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@return The size of the current receive window, in bytes.
**/
UINT32
TcpRcvWinNow (
IN TCP_CB *Tcb
);
/**
Get the maximum SndNxt.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@return The sequence number of the maximum SndNxt.
**/
TCP_SEQNO
TcpGetMaxSndNxt (
IN TCP_CB *Tcb
);
/**
Compute how much data to send.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Force If TRUE, ignore the sender's SWS avoidance algorithm
and send out data by force.
@return The length of the data that can be sent. If 0, no data can be sent.
**/
UINT32
TcpDataToSend (
IN TCP_CB *Tcb,
IN INTN Force
);
/**
Retransmit the segment from sequence Seq.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Seq The sequence number of the segment to be retransmitted.
@retval 0 The retransmission succeeded.
@retval -1 An error condition occurred.
**/
INTN
TcpRetransmit (
IN TCP_CB *Tcb,
IN TCP_SEQNO Seq
);
/**
Check whether to send data/SYN/FIN and piggyback an ACK.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Force If TRUE, ignore the sender's SWS avoidance algorithm
and send out data by force.
@return The number of bytes sent.
**/
INTN
TcpToSendData (
IN OUT TCP_CB *Tcb,
IN INTN Force
);
/**
Check whether to send an ACK or delayed ACK.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpToSendAck (
IN OUT TCP_CB *Tcb
);
/**
Send an ACK immediately.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpSendAck (
IN OUT TCP_CB *Tcb
);
/**
Send a zero probe segment. It can be used by keepalive and zero window probe.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@retval 0 The zero probe segment was sent out successfully.
@retval other An error condition occurred.
**/
INTN
TcpSendZeroProbe (
IN OUT TCP_CB *Tcb
);
/**
Send a RESET segment in response to the segment received.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
@param[in] Head TCP header of the segment that triggers the reset.
@param[in] Len Length of the segment that triggers the reset.
@param[in] Local Local IP address.
@param[in] Remote Remote peer's IP address.
@param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,
IP_VERSION_6 indicates TCP is running on IP6 stack.
@retval 0 A reset is sent or no need to send it.
@retval -1 No reset is sent.
**/
INTN
TcpSendReset (
IN TCP_CB *Tcb,
IN TCP_HEAD *Head,
IN INT32 Len,
IN EFI_IP_ADDRESS *Local,
IN EFI_IP_ADDRESS *Remote,
IN UINT8 Version
);
/**
Verify that the segment is in good shape.
@param[in] Nbuf Buffer that contains the segment to be checked.
@retval 0 The segment is broken.
@retval 1 The segment is in good shape.
**/
INTN
TcpVerifySegment (
IN NET_BUF *Nbuf
);
//
// Functions from TcpInput.c
//
/**
Process the received ICMP error messages for TCP.
@param[in] Nbuf Buffer that contains part of the TCP segment without IP header
truncated from the ICMP error packet.
@param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.
@param[in] Src Source address of the ICMP error message.
@param[in] Dst Destination address of the ICMP error message.
@param[in] Version IP_VERSION_4 indicates IP4 stack, IP_VERSION_6 indicates
IP6 stack.
**/
VOID
TcpIcmpInput (
IN NET_BUF *Nbuf,
IN UINT8 IcmpErr,
IN EFI_IP_ADDRESS *Src,
IN EFI_IP_ADDRESS *Dst,
IN UINT8 Version
);
/**
Process the received TCP segments.
@param[in] Nbuf Buffer that contains received TCP segment without an IP header.
@param[in] Src Source address of the segment, or the peer's IP address.
@param[in] Dst Destination address of the segment, or the local end's IP
address.
@param[in] Version IP_VERSION_4 indicates IP4 stack, IP_VERSION_6 indicates
IP6 stack.
@retval 0 The segment processed successfully. It is either accepted or
discarded. But no connection is reset by the segment.
@retval -1 A connection is reset by the segment.
**/
INTN
TcpInput (
IN NET_BUF *Nbuf,
IN EFI_IP_ADDRESS *Src,
IN EFI_IP_ADDRESS *Dst,
IN UINT8 Version
);
//
// Functions in TcpTimer.c
//
/**
Close the TCP connection.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpClose (
IN OUT TCP_CB *Tcb
);
/**
Heart beat timer handler, queues the DPC at TPL_CALLBACK.
@param[in] Event Timer event signaled, ignored.
@param[in] Context Context of the timer event, ignored.
**/
VOID
EFIAPI
TcpTicking (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Enable a TCP timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Timer The index of the timer to be enabled.
@param[in] TimeOut The timeout value of this timer.
**/
VOID
TcpSetTimer (
IN OUT TCP_CB *Tcb,
IN UINT16 Timer,
IN UINT32 TimeOut
);
/**
Clear one TCP timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Timer The index of the timer to be cleared.
**/
VOID
TcpClearTimer (
IN OUT TCP_CB *Tcb,
IN UINT16 Timer
);
/**
Clear all TCP timers.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpClearAllTimer (
IN OUT TCP_CB *Tcb
);
/**
Enable the window prober timer and set the timeout value.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpSetProbeTimer (
IN OUT TCP_CB *Tcb
);
/**
Enable the keepalive timer and set the timeout value.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpSetKeepaliveTimer (
IN OUT TCP_CB *Tcb
);
//
// Functions in TcpIo.c
//
/**
Packet receive callback function provided to IP_IO. Used to call
the proper function to handle the packet received by IP.
@param[in] Status Result of the receive request.
@param[in] IcmpErr Valid when Status is EFI_ICMP_ERROR.
@param[in] NetSession The IP session for the received packet.
@param[in] Pkt Packet received.
@param[in] Context The data provided by the user for the received packet when
the callback is registered in IP_IO_OPEN_DATA::RcvdContext.
This is an optional parameter that may be NULL.
**/
VOID
EFIAPI
TcpRxCallback (
IN EFI_STATUS Status,
IN UINT8 IcmpErr,
IN EFI_NET_SESSION_DATA *NetSession,
IN NET_BUF *Pkt,
IN VOID *Context OPTIONAL
);
/**
Send the segment to IP via IpIo function.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the TCP segment to be sent.
@param[in] Src Source address of the TCP segment.
@param[in] Dest Destination address of the TCP segment.
@param[in] Version IP_VERSION_4 or IP_VERSION_6
@retval 0 The segment was sent out successfully.
@retval -1 The segment failed to be sent.
**/
INTN
TcpSendIpPacket (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf,
IN EFI_IP_ADDRESS *Src,
IN EFI_IP_ADDRESS *Dest,
IN UINT8 Version
);
/**
Refresh the remote peer's Neighbor Cache State if already exists.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Neighbor Source address of the TCP segment.
@param[in] Timeout Time in 100-ns units that this entry will remain
in the neighbor cache. A value of zero means that
the entry is permanent. A value of non-zero means
that the entry is dynamic and will be deleted
after Timeout.
@retval EFI_SUCCESS Successfully updated the neighbor relationship.
@retval EFI_NOT_STARTED The IpIo is not configured.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
@retval EFI_NOT_FOUND This entry is not in the neighbor table.
**/
EFI_STATUS
Tcp6RefreshNeighbor (
IN TCP_CB *Tcb,
IN EFI_IP_ADDRESS *Neighbor,
IN UINT32 Timeout
);
//
// Functions in TcpDispatcher.c
//
/**
The procotol handler provided to the socket layer, used to
dispatch the socket level requests by calling the corresponding
TCP layer functions.
@param[in] Sock Pointer to the socket of this TCP instance.
@param[in] Request The code of this operation request.
@param[in] Data Pointer to the operation specific data passed in
together with the operation request. This is an
optional parameter that may be NULL.
@retval EFI_SUCCESS The socket request completed successfully.
@retval other The error status returned by the corresponding TCP
layer function.
**/
EFI_STATUS
TcpDispatcher (
IN SOCKET *Sock,
IN UINT8 Request,
IN VOID *Data OPTIONAL
);
#endif

1592
NetworkPkg/TcpDxe/TcpInput.c Normal file

File diff suppressed because it is too large Load Diff

190
NetworkPkg/TcpDxe/TcpIo.c Normal file
View File

@@ -0,0 +1,190 @@
/** @file
Implementation of I/O interfaces between TCP and IpIoLib.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
/**
Packet receive callback function provided to IP_IO, used to call
the proper function to handle the packet received by IP.
@param[in] Status Result of the receive request.
@param[in] IcmpErr Valid when Status is EFI_ICMP_ERROR.
@param[in] NetSession The IP session for the received packet.
@param[in] Pkt Packet received.
@param[in] Context The data provided by the user for the received packet when
the callback is registered in IP_IO_OPEN_DATA::RcvdContext.
This is an optional parameter that may be NULL.
**/
VOID
EFIAPI
TcpRxCallback (
IN EFI_STATUS Status,
IN UINT8 IcmpErr,
IN EFI_NET_SESSION_DATA *NetSession,
IN NET_BUF *Pkt,
IN VOID *Context OPTIONAL
)
{
if (EFI_SUCCESS == Status) {
TcpInput (Pkt, &NetSession->Source, &NetSession->Dest, NetSession->IpVersion);
} else {
TcpIcmpInput (
Pkt,
IcmpErr,
&NetSession->Source,
&NetSession->Dest,
NetSession->IpVersion
);
}
}
/**
Send the segment to IP via IpIo function.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the TCP segment to be sent.
@param[in] Src Source address of the TCP segment.
@param[in] Dest Destination address of the TCP segment.
@param[in] Version IP_VERSION_4 or IP_VERSION_6
@retval 0 The segment was sent out successfully.
@retval -1 The segment failed to send.
**/
INTN
TcpSendIpPacket (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf,
IN EFI_IP_ADDRESS *Src,
IN EFI_IP_ADDRESS *Dest,
IN UINT8 Version
)
{
EFI_STATUS Status;
IP_IO *IpIo;
IP_IO_OVERRIDE Override;
SOCKET *Sock;
VOID *IpSender;
TCP_PROTO_DATA *TcpProto;
if (NULL == Tcb) {
IpIo = NULL;
IpSender = IpIoFindSender (&IpIo, Version, Src);
if (IpSender == NULL) {
DEBUG ((EFI_D_WARN, "TcpSendIpPacket: No appropriate IpSender.\n"));
return -1;
}
if (Version == IP_VERSION_6) {
//
// It's tricky here. EFI IPv6 Spec don't allow an instance overriding the
// destination address if the dest is already specified through the
// configuration data. Here we get the IpIo we need and use the default IP
// instance in this IpIo to send the packet. The dest address is configured
// to be the unspecified address for the default IP instance.
//
IpSender = NULL;
}
} else {
Sock = Tcb->Sk;
TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
IpIo = TcpProto->TcpService->IpIo;
IpSender = Tcb->IpInfo;
if (Version == IP_VERSION_6) {
//
// It's IPv6 and this TCP segment belongs to a solid TCB, in such case
// the destination address can't be overridden, so reset the Dest to NULL.
//
Dest = NULL;
}
}
ASSERT (Version == IpIo->IpVersion);
if (Version == IP_VERSION_4) {
Override.Ip4OverrideData.TypeOfService = 0;
Override.Ip4OverrideData.TimeToLive = 255;
Override.Ip4OverrideData.DoNotFragment = FALSE;
Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_TCP;
ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
CopyMem (&Override.Ip4OverrideData.SourceAddress, Src, sizeof (EFI_IPv4_ADDRESS));
} else {
Override.Ip6OverrideData.Protocol = EFI_IP_PROTO_TCP;
Override.Ip6OverrideData.HopLimit = 255;
Override.Ip6OverrideData.FlowLabel = 0;
}
Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "TcpSendIpPacket: return %r error\n", Status));
return -1;
}
return 0;
}
/**
Refresh the remote peer's Neighbor Cache State if already exists.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Neighbor Source address of the TCP segment.
@param[in] Timeout Time in 100-ns units that this entry will remain
in the neighbor cache. A value of zero means that
the entry is permanent. A value of non-zero means
that the entry is dynamic and will be deleted
after Timeout.
@retval EFI_SUCCESS Successfully updated the neighbor relationship.
@retval EFI_NOT_STARTED The IpIo is not configured.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
@retval EFI_NOT_FOUND This entry is not in the neighbor table.
**/
EFI_STATUS
Tcp6RefreshNeighbor (
IN TCP_CB *Tcb,
IN EFI_IP_ADDRESS *Neighbor,
IN UINT32 Timeout
)
{
IP_IO *IpIo;
SOCKET *Sock;
TCP_PROTO_DATA *TcpProto;
if (NULL == Tcb) {
IpIo = NULL;
IpIoFindSender (&IpIo, IP_VERSION_6, Neighbor);
if (IpIo == NULL) {
DEBUG ((EFI_D_WARN, "Tcp6AddNeighbor: No appropriate IpIo.\n"));
return EFI_NOT_STARTED;
}
} else {
Sock = Tcb->Sk;
TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
IpIo = TcpProto->TcpService->IpIo;
}
return IpIoRefreshNeighbor (IpIo, Neighbor, Timeout);
}

1074
NetworkPkg/TcpDxe/TcpMain.c Normal file

File diff suppressed because it is too large Load Diff

758
NetworkPkg/TcpDxe/TcpMain.h Normal file
View File

@@ -0,0 +1,758 @@
/** @file
Declaration of protocol interfaces in EFI_TCP4_PROTOCOL and EFI_TCP6_PROTOCOL.
It is the common head file for all Tcp*.c in TCP driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _TCP_MAIN_H_
#define _TCP_MAIN_H_
#include <Protocol/ServiceBinding.h>
#include <Protocol/DriverBinding.h>
#include <Library/IpIoLib.h>
#include <Library/DevicePathLib.h>
#include "Socket.h"
#include "TcpProto.h"
#include "TcpDriver.h"
#include "TcpFunc.h"
extern UINT16 mTcp4RandomPort;
extern UINT16 mTcp6RandomPort;
extern CHAR16 *mTcpStateName[];
extern EFI_COMPONENT_NAME_PROTOCOL gTcpComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gTcpComponentName2;
extern LIST_ENTRY mTcpRunQue;
extern LIST_ENTRY mTcpListenQue;
extern TCP_SEQNO mTcpGlobalIss;
extern UINT32 mTcpTick;
///
/// 30 seconds.
///
#define TCP6_KEEP_NEIGHBOR_TIME 30
///
/// 5 seconds, since 1 tick equals 200ms.
///
#define TCP6_REFRESH_NEIGHBOR_TICK 25
#define TCP_EXPIRE_TIME 65535
///
/// The implementation selects the initial send sequence number and the unit to
/// be added when it is increased.
///
#define TCP_BASE_ISS 0x4d7e980b
#define TCP_ISS_INCREMENT_1 2048
#define TCP_ISS_INCREMENT_2 100
typedef union {
EFI_TCP4_CONFIG_DATA Tcp4CfgData;
EFI_TCP6_CONFIG_DATA Tcp6CfgData;
} TCP_CONFIG_DATA;
typedef union {
EFI_TCP4_ACCESS_POINT Tcp4Ap;
EFI_TCP6_ACCESS_POINT Tcp6Ap;
} TCP_ACCESS_POINT;
typedef struct _TCP4_MODE_DATA {
EFI_TCP4_CONNECTION_STATE *Tcp4State;
EFI_TCP4_CONFIG_DATA *Tcp4ConfigData;
EFI_IP4_MODE_DATA *Ip4ModeData;
EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData;
EFI_SIMPLE_NETWORK_MODE *SnpModeData;
} TCP4_MODE_DATA;
typedef struct _TCP6_MODE_DATA {
EFI_TCP6_CONNECTION_STATE *Tcp6State;
EFI_TCP6_CONFIG_DATA *Tcp6ConfigData;
EFI_IP6_MODE_DATA *Ip6ModeData;
EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData;
EFI_SIMPLE_NETWORK_MODE *SnpModeData;
} TCP6_MODE_DATA;
typedef struct _TCP4_ROUTE_INFO {
BOOLEAN DeleteRoute;
EFI_IPv4_ADDRESS *SubnetAddress;
EFI_IPv4_ADDRESS *SubnetMask;
EFI_IPv4_ADDRESS *GatewayAddress;
} TCP4_ROUTE_INFO;
//
// EFI_TCP4_PROTOCOL definitions.
//
/**
Get the current operational status.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[out] Tcp4State Pointer to the buffer to receive the current TCP
state. Optional parameter that may be NULL.
@param[out] Tcp4ConfigData Pointer to the buffer to receive the current TCP
configuration. Optional parameter that may be NULL.
@param[out] Ip4ModeData Pointer to the buffer to receive the current
IPv4 configuration. Optional parameter that may be NULL.
@param[out] MnpConfigData Pointer to the buffer to receive the current MNP
configuration data indirectly used by the TCPv4
Instance. Optional parameter that may be NULL.
@param[out] SnpModeData Pointer to the buffer to receive the current SNP
configuration data indirectly used by the TCPv4
Instance. Optional parameter that may be NULL.
@retval EFI_SUCCESS The mode data was read.
@retval EFI_NOT_STARTED No configuration data is available because this
instance hasn't been started.
@retval EFI_INVALID_PARAMETER This is NULL.
**/
EFI_STATUS
EFIAPI
Tcp4GetModeData (
IN CONST EFI_TCP4_PROTOCOL *This,
OUT EFI_TCP4_CONNECTION_STATE *Tcp4State OPTIONAL,
OUT EFI_TCP4_CONFIG_DATA *Tcp4ConfigData OPTIONAL,
OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
);
/**
Initialize or brutally reset the operational parameters for
this EFI TCPv4 instance.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] TcpConfigData Pointer to the configure data to configure the
instance. Optional parameter that may be NULL.
@retval EFI_SUCCESS The operational settings are set, changed, or
reset successfully.
@retval EFI_NO_MAPPING When using a default address, configuration
(through DHCP, BOOTP, RARP, etc.) is not
finished.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_ACCESS_DENIED Configuring the TCP instance when it is already
configured.
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
@retval EFI_UNSUPPORTED One or more of the control options are not
supported in the implementation.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.
**/
EFI_STATUS
EFIAPI
Tcp4Configure (
IN EFI_TCP4_PROTOCOL * This,
IN EFI_TCP4_CONFIG_DATA * TcpConfigData OPTIONAL
);
/**
Add or delete routing entries.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] DeleteRoute If TRUE, delete the specified route from routing
table; if FALSE, add the specified route to
routing table.
@param[in] SubnetAddress The destination network.
@param[in] SubnetMask The subnet mask for the destination network.
@param[in] GatewayAddress The gateway address for this route.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance has not been
configured.
@retval EFI_NO_MAPPING When using a default address, configuration
(through DHCP, BOOTP, RARP, etc.) is not
finished.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to add the
entry to the routing table.
@retval EFI_NOT_FOUND This route is not in the routing table.
@retval EFI_ACCESS_DENIED This route is already in the routing table.
@retval EFI_UNSUPPORTED The TCP driver does not support this operation.
**/
EFI_STATUS
EFIAPI
Tcp4Routes (
IN EFI_TCP4_PROTOCOL *This,
IN BOOLEAN DeleteRoute,
IN EFI_IPv4_ADDRESS *SubnetAddress,
IN EFI_IPv4_ADDRESS *SubnetMask,
IN EFI_IPv4_ADDRESS *GatewayAddress
);
/**
Initiate a nonblocking TCP connection request for an active TCP instance.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] ConnectionToken Pointer to the connection token to return when
the TCP three way handshake finishes.
@retval EFI_SUCCESS The connection request is successfully
initiated.
@retval EFI_NOT_STARTED This EFI_TCP4_PROTOCOL instance hasn't been
configured.
@retval EFI_ACCESS_DENIED The instance is not configured as an active one
or it is not in Tcp4StateClosed state.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES The driver can't allocate enough resources to
initiate the active open.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
Tcp4Connect (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken
);
/**
Listen on the passive instance to accept an incoming connection request.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] ListenToken Pointer to the listen token to return when
operation finishes.
@retval EFI_SUCCESS The listen token has been queued successfully.
@retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been
configured.
@retval EFI_ACCESS_DENIED The instatnce is not a passive one or it is not
in Tcp4StateListen state, or a same listen token
has already existed in the listen token queue of
this TCP instance.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to finish
the operation.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
Tcp4Accept (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_LISTEN_TOKEN *ListenToken
);
/**
Queues outgoing data into the transmit queue
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance
@param[in] Token Pointer to the completion token to queue to the
transmit queue
@retval EFI_SUCCESS The data has been queued for transmission
@retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been
configured.
@retval EFI_NO_MAPPING When using a default address, configuration
(DHCP, BOOTP, RARP, etc.) is not finished yet.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid
@retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE:
* A transmit completion token with the same
Token-> CompletionToken.Event was already in the
transmission queue. * The current instance is in
Tcp4StateClosed state * The current instance is
a passive one and it is in Tcp4StateListen
state. * User has called Close() to disconnect
this connection.
@retval EFI_NOT_READY The completion token could not be queued because
the transmit queue is full.
@retval EFI_OUT_OF_RESOURCES Could not queue the transmit data because of a
resource shortage.
@retval EFI_NETWORK_UNREACHABLE There is no route to the destination network or
address.
**/
EFI_STATUS
EFIAPI
Tcp4Transmit (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_IO_TOKEN *Token
);
/**
Place an asynchronous receive request into the receiving queue.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] Token Pointer to a token that is associated with the
receive data descriptor.
@retval EFI_SUCCESS The receive completion token was cached.
@retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been
configured.
@retval EFI_NO_MAPPING When using a default address, configuration
(DHCP, BOOTP, RARP, etc.) is not finished yet.
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued
due to a lack of system resources.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE:
* A receive completion token with the same
Token->CompletionToken.Event was already in the
receive queue. * The current instance is in
Tcp4StateClosed state. * The current instance is
a passive one and it is in Tcp4StateListen
state. * User has called Close() to disconnect
this connection.
@retval EFI_CONNECTION_FIN The communication peer has closed the connection
and there is no buffered data in the receive
buffer of this instance.
@retval EFI_NOT_READY The receive request could not be queued because
the receive queue is full.
**/
EFI_STATUS
EFIAPI
Tcp4Receive (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_IO_TOKEN *Token
);
/**
Disconnecting a TCP connection gracefully or reset a TCP connection.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] CloseToken Pointer to the close token to return when
operation finishes.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been
configured.
@retval EFI_ACCESS_DENIED One or more of the following are TRUE: *
Configure() has been called with TcpConfigData
set to NULL and this function has not returned.
* Previous Close() call on this instance has not
finished.
@retval EFI_INVALID_PARAMETER One ore more parameters are invalid.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to finish the
operation.
@retval EFI_DEVICE_ERROR Any unexpected error not belonging to the error
categories given above.
**/
EFI_STATUS
EFIAPI
Tcp4Close (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_CLOSE_TOKEN *CloseToken
);
/**
Abort an asynchronous connection, listen, transmission or receive request.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@param[in] Token Pointer to a token that has been issued by
Connect(), Accept(), Transmit() or Receive(). If
NULL, all pending tokens issued by the above four
functions will be aborted.
@retval EFI_UNSUPPORTED The operation is not supported in the current
implementation.
**/
EFI_STATUS
EFIAPI
Tcp4Cancel (
IN EFI_TCP4_PROTOCOL *This,
IN EFI_TCP4_COMPLETION_TOKEN *Token OPTIONAL
);
/**
Poll to receive incoming data and transmit outgoing segments.
@param[in] This Pointer to the EFI_TCP4_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_NOT_READY No incoming or outgoing data was processed.
@retval EFI_TIMEOUT Data was dropped out of the transmission or
receive queue. Consider increasing the polling
rate.
**/
EFI_STATUS
EFIAPI
Tcp4Poll (
IN EFI_TCP4_PROTOCOL *This
);
//
// EFI_TCP6_PROTOCOL definitions.
//
/**
Get the current operational status.
The GetModeData() function copies the current operational settings of this EFI TCPv6
Protocol instance into user-supplied buffers. This function can also be used to retrieve
the operational setting of underlying drivers such as IPv6, MNP, or SNP.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[out] Tcp6State The buffer in which the current TCP state is
returned. Optional parameter that may be NULL.
@param[out] Tcp6ConfigData The buffer in which the current TCP configuration
is returned. Optional parameter that may be NULL.
@param[out] Ip6ModeData The buffer in which the current IPv6 configuration
data used by the TCP instance is returned.
Optional parameter that may be NULL.
@param[out] MnpConfigData The buffer in which the current MNP configuration
data used indirectly by the TCP instance is returned.
Optional parameter that may be NULL.
@param[out] SnpModeData The buffer in which the current SNP mode data
used indirectly by the TCP instance is returned.
Optional parameter that may be NULL.
@retval EFI_SUCCESS The mode data was read.
@retval EFI_NOT_STARTED No configuration data is available because this instance hasn't
been started.
@retval EFI_INVALID_PARAMETER This is NULL.
**/
EFI_STATUS
EFIAPI
Tcp6GetModeData (
IN EFI_TCP6_PROTOCOL *This,
OUT EFI_TCP6_CONNECTION_STATE *Tcp6State OPTIONAL,
OUT EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL,
OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL,
OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
);
/**
Initialize or brutally reset the operational parameters for this EFI TCPv6 instance.
The Configure() function does the following:
- Initialize this TCP instance, i.e., initialize the communication end settings and
specify active open or passive open for an instance.
- Reset this TCP instance brutally, i.e., cancel all pending asynchronous tokens, flush
transmission and receiving buffer directly without informing the communication peer.
No other TCPv6 Protocol operation except Poll() can be executed by this instance until
it is configured properly. For an active TCP instance, after a proper configuration it
may call Connect() to initiates the three-way handshake. For a passive TCP instance,
its state will transit to Tcp6StateListen after configuration, and Accept() may be
called to listen the incoming TCP connection requests. If Tcp6ConfigData is set to NULL,
the instance is reset. Resetting process will be done brutally, the state machine will
be set to Tcp6StateClosed directly, the receive queue and transmit queue will be flushed,
and no traffic is allowed through this instance.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] Tcp6ConfigData Pointer to the configure data to configure the instance.
If Tcp6ConfigData is set to NULL, the instance is reset.
@retval EFI_SUCCESS The operational settings were set, changed, or reset
successfully.
@retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
address for this instance, but no source address was available for
use.
@retval EFI_INVALID_PARAMETER One or more of the following conditions are TRUE:
- This is NULL.
- Tcp6ConfigData->AccessPoint.StationAddress is neither zero nor
one of the configured IP addresses in the underlying IPv6 driver.
- Tcp6ConfigData->AccessPoint.RemoteAddress isn't a valid unicast
IPv6 address.
- Tcp6ConfigData->AccessPoint.RemoteAddress is zero or
Tcp6ConfigData->AccessPoint.RemotePort is zero when
Tcp6ConfigData->AccessPoint.ActiveFlag is TRUE.
- A same access point has been configured in other TCP
instance properly.
@retval EFI_ACCESS_DENIED Configuring TCP instance when it is configured without
calling Configure() with NULL to reset it.
@retval EFI_UNSUPPORTED One or more of the control options are not supported in
the implementation.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when
executing Configure().
@retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
**/
EFI_STATUS
EFIAPI
Tcp6Configure (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL
);
/**
Initiate a nonblocking TCP connection request for an active TCP instance.
The Connect() function will initiate an active open to the remote peer configured
in current TCP instance if it is configured active. If the connection succeeds or
fails due to an error, the ConnectionToken->CompletionToken.Event will be signaled,
and ConnectionToken->CompletionToken.Status will be updated accordingly. This
function can only be called for the TCP instance in Tcp6StateClosed state. The
instance will transfer into Tcp6StateSynSent if the function returns EFI_SUCCESS.
If TCP three-way handshake succeeds, its state will become Tcp6StateEstablished;
otherwise, the state will return to Tcp6StateClosed.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] ConnectionToken Pointer to the connection token to return when the TCP
three-way handshake finishes.
@retval EFI_SUCCESS The connection request successfully initiated and the state of
this TCP instance has been changed to Tcp6StateSynSent.
@retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured.
@retval EFI_ACCESS_DENIED One or more of the following conditions are TRUE:
- This instance is not configured as an active instance.
- This instance is not in Tcp6StateClosed state.
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
- This is NULL.
- ConnectionToken is NULL.
- ConnectionToken->CompletionToken.Event is NULL.
@retval EFI_OUT_OF_RESOURCES The driver can't allocate enough resources to initiate the active open.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
Tcp6Connect (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_CONNECTION_TOKEN *ConnectionToken
);
/**
Listen on the passive instance to accept an incoming connection request. This is a
nonblocking operation.
The Accept() function initiates an asynchronous accept request to wait for an incoming
connection on the passive TCP instance. If a remote peer successfully establishes a
connection with this instance, a new TCP instance will be created and its handle will
be returned in ListenToken->NewChildHandle. The newly created instance is configured
by inheriting the passive instance's configuration, and is ready for use upon return.
The new instance is in the Tcp6StateEstablished state.
The ListenToken->CompletionToken.Event will be signaled when a new connection is
accepted, user aborts the listen or connection is reset.
This function only can be called when the current TCP instance is in Tcp6StateListen state.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] ListenToken Pointer to the listen token to return when the operation finishes.
@retval EFI_SUCCESS The listen token was been queued successfully.
@retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured.
@retval EFI_ACCESS_DENIED One or more of the following are TRUE:
- This instance is not a passive instance.
- This instance is not in Tcp6StateListen state.
- The same listen token has already existed in the listen
token queue of this TCP instance.
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
- This is NULL.
- ListenToken is NULL.
- ListentToken->CompletionToken.Event is NULL.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to finish the operation.
@retval EFI_DEVICE_ERROR Any unexpected error not belonging to the error
categories given above.
**/
EFI_STATUS
EFIAPI
Tcp6Accept (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_LISTEN_TOKEN *ListenToken
);
/**
Queues outgoing data into the transmit queue.
The Transmit() function queues a sending request to this TCP instance along with the
user data. The status of the token is updated and the event in the token will be
signaled once the data is sent out or some error occurs.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] Token Pointer to the completion token to queue to the transmit queue.
@retval EFI_SUCCESS The data has been queued for transmission.
@retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured.
@retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a
source address for this instance, but no source address was
available for use.
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
- This is NULL.
- Token is NULL.
- Token->CompletionToken.Event is NULL.
- Token->Packet.TxData is NULL.
- Token->Packet.FragmentCount is zero.
- Token->Packet.DataLength is not equal to the sum of fragment lengths.
@retval EFI_ACCESS_DENIED One or more of the following conditions are TRUE:
- A transmit completion token with the same Token->
CompletionToken.Event was already in the
transmission queue.
- The current instance is in Tcp6StateClosed state.
- The current instance is a passive one and it is in
Tcp6StateListen state.
- User has called Close() to disconnect this connection.
@retval EFI_NOT_READY The completion token could not be queued because the
transmit queue is full.
@retval EFI_OUT_OF_RESOURCES Could not queue the transmit data because of a resource
shortage.
@retval EFI_NETWORK_UNREACHABLE There is no route to the destination network or address.
**/
EFI_STATUS
EFIAPI
Tcp6Transmit (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_IO_TOKEN *Token
);
/**
Places an asynchronous receive request into the receiving queue.
The Receive() function places a completion token into the receive packet queue. This
function is always asynchronous. The caller must allocate the Token->CompletionToken.Event
and the FragmentBuffer used to receive data. The caller also must fill the DataLength, which
represents the whole length of all FragmentBuffer. When the receive operation completes, the
EFI TCPv6 Protocol driver updates the Token->CompletionToken.Status and Token->Packet.RxData
fields, and the Token->CompletionToken.Event is signaled. If data is obtained, the data and its length
will be copied into the FragmentTable. At the same time the full length of received data will
be recorded in the DataLength fields. Providing a proper notification function and context
for the event enables the user to receive the notification and receiving status. That
notification function is guaranteed to not be re-entered.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] Token Pointer to a token that is associated with the receive data
descriptor.
@retval EFI_SUCCESS The receive completion token was cached.
@retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured.
@retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source
address for this instance, but no source address was available for use.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- This is NULL.
- Token is NULL.
- Token->CompletionToken.Event is NULL.
- Token->Packet.RxData is NULL.
- Token->Packet.RxData->DataLength is 0.
- The Token->Packet.RxData->DataLength is not the
sum of all FragmentBuffer length in FragmentTable.
@retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of
system resources (usually memory).
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
The EFI TCPv6 Protocol instance has been reset to startup defaults.
@retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE:
- A receive completion token with the same Token->CompletionToken.Event
was already in the receive queue.
- The current instance is in Tcp6StateClosed state.
- The current instance is a passive one and it is in
Tcp6StateListen state.
- The user has called Close() to disconnect this connection.
@retval EFI_CONNECTION_FIN The communication peer has closed the connection, and there is no
buffered data in the receive buffer of this instance.
@retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
**/
EFI_STATUS
EFIAPI
Tcp6Receive (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_IO_TOKEN *Token
);
/**
Disconnecting a TCP connection gracefully or reset a TCP connection. This function is a
nonblocking operation.
Initiate an asynchronous close token to the TCP driver. After Close() is called, any buffered
transmission data will be sent by the TCP driver, and the current instance will have a graceful close
working flow described as RFC 793 if AbortOnClose is set to FALSE, otherwise, a rest packet
will be sent by TCP driver to fast disconnect this connection. When the close operation completes
successfully the TCP instance is in Tcp6StateClosed state, all pending asynchronous
operations are signaled, and any buffers used for TCP network traffic are flushed.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] CloseToken Pointer to the close token to return when operation finishes.
@retval EFI_SUCCESS The Close() was called successfully.
@retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured.
@retval EFI_ACCESS_DENIED One or more of the following are TRUE:
- CloseToken or CloseToken->CompletionToken.Event is already in use.
- Previous Close() call on this instance has not finished.
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
- This is NULL.
- CloseToken is NULL.
- CloseToken->CompletionToken.Event is NULL.
@retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to finish the operation.
@retval EFI_DEVICE_ERROR Any unexpected error not belonging to the error categories given above.
**/
EFI_STATUS
EFIAPI
Tcp6Close (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_CLOSE_TOKEN *CloseToken
);
/**
Abort an asynchronous connection, listen, transmission or receive request.
The Cancel() function aborts a pending connection, listen, transmit or
receive request.
If Token is not NULL and the token is in the connection, listen, transmission
or receive queue when it is being cancelled, its Token->Status will be set
to EFI_ABORTED and then Token->Event will be signaled.
If the token is not in one of the queues, which usually means that the
asynchronous operation has completed, EFI_NOT_FOUND is returned.
If Token is NULL all asynchronous token issued by Connect(), Accept(),
Transmit() and Receive() will be aborted.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@param[in] Token Pointer to a token that has been issued by
EFI_TCP6_PROTOCOL.Connect(),
EFI_TCP6_PROTOCOL.Accept(),
EFI_TCP6_PROTOCOL.Transmit() or
EFI_TCP6_PROTOCOL.Receive(). If NULL, all pending
tokens issued by above four functions will be aborted. Type
EFI_TCP6_COMPLETION_TOKEN is defined in
EFI_TCP_PROTOCOL.Connect().
@retval EFI_UNSUPPORTED The implementation does not support this function.
**/
EFI_STATUS
EFIAPI
Tcp6Cancel (
IN EFI_TCP6_PROTOCOL *This,
IN EFI_TCP6_COMPLETION_TOKEN *Token OPTIONAL
);
/**
Poll to receive incoming data and transmit outgoing segments.
The Poll() function increases the rate that data is moved between the network
and application and can be called when the TCP instance is created successfully.
Its use is optional.
@param[in] This Pointer to the EFI_TCP6_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_NOT_READY No incoming or outgoing data is processed.
@retval EFI_TIMEOUT Data was dropped out of the transmission or receive queue.
Consider increasing the polling rate.
**/
EFI_STATUS
EFIAPI
Tcp6Poll (
IN EFI_TCP6_PROTOCOL *This
);
#endif

1281
NetworkPkg/TcpDxe/TcpMisc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,374 @@
/** @file
Routines to process TCP option.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
/**
Get a UINT16 value from buffer.
@param[in] Buf Pointer to input buffer.
@return The UINT16 value obtained from the buffer.
**/
UINT16
TcpGetUint16 (
IN UINT8 *Buf
)
{
UINT16 Value;
CopyMem (&Value, Buf, sizeof (UINT16));
return NTOHS (Value);
}
/**
Get a UINT32 value from buffer.
@param[in] Buf Pointer to input buffer.
@return The UINT32 value obtained from the buffer.
**/
UINT32
TcpGetUint32 (
IN UINT8 *Buf
)
{
UINT32 Value;
CopyMem (&Value, Buf, sizeof (UINT32));
return NTOHL (Value);
}
/**
Put a UINT32 value in buffer.
@param[out] Buf Pointer to the buffer.
@param[in] Data The UINT32 Date to put in the buffer.
**/
VOID
TcpPutUint32 (
OUT UINT8 *Buf,
IN UINT32 Data
)
{
Data = HTONL (Data);
CopyMem (Buf, &Data, sizeof (UINT32));
}
/**
Compute the window scale value according to the given buffer size.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@return The scale value.
**/
UINT8
TcpComputeScale (
IN TCP_CB *Tcb
)
{
UINT8 Scale;
UINT32 BufSize;
ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);
Scale = 0;
while ((Scale < TCP_OPTION_MAX_WS) && ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {
Scale++;
}
return Scale;
}
/**
Build the TCP option in three-way handshake.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the buffer to store the options.
@return The total length of the TCP option field.
**/
UINT16
TcpSynBuildOption (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
)
{
UINT8 *Data;
UINT16 Len;
ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
Len = 0;
//
// Add a timestamp option if not disabled by the application
// and it is the first SYN segment, or the peer has sent
// us its timestamp.
//
if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&
(!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))
) {
Data = NetbufAllocSpace (
Nbuf,
TCP_OPTION_TS_ALIGNED_LEN,
NET_BUF_HEAD
);
ASSERT (Data != NULL);
Len += TCP_OPTION_TS_ALIGNED_LEN;
TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
TcpPutUint32 (Data + 4, mTcpTick);
TcpPutUint32 (Data + 8, 0);
}
//
// Build window scale option, only when configured
// to send WS option, and either we are doing active
// open or we have received WS option from peer.
//
if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&
(!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))
) {
Data = NetbufAllocSpace (
Nbuf,
TCP_OPTION_WS_ALIGNED_LEN,
NET_BUF_HEAD
);
ASSERT (Data != NULL);
Len += TCP_OPTION_WS_ALIGNED_LEN;
TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));
}
//
// Build the MSS option.
//
Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);
ASSERT (Data != NULL);
Len += TCP_OPTION_MSS_LEN;
TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);
return Len;
}
/**
Build the TCP option in synchronized states.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the buffer to store the options.
@return The total length of the TCP option field.
**/
UINT16
TcpBuildOption (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
)
{
UINT8 *Data;
UINT16 Len;
ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
Len = 0;
//
// Build the Timestamp option.
//
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&
!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)
) {
Data = NetbufAllocSpace (
Nbuf,
TCP_OPTION_TS_ALIGNED_LEN,
NET_BUF_HEAD
);
ASSERT (Data != NULL);
Len += TCP_OPTION_TS_ALIGNED_LEN;
TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
TcpPutUint32 (Data + 4, mTcpTick);
TcpPutUint32 (Data + 8, Tcb->TsRecent);
}
return Len;
}
/**
Parse the supported options.
@param[in] Tcp Pointer to the TCP_CB of this TCP instance.
@param[in, out] Option Pointer to the TCP_OPTION used to store the
successfully pasrsed options.
@retval 0 The options are successfully pasrsed.
@retval -1 Ilegal option was found.
**/
INTN
TcpParseOption (
IN TCP_HEAD *Tcp,
IN OUT TCP_OPTION *Option
)
{
UINT8 *Head;
UINT8 TotalLen;
UINT8 Cur;
UINT8 Type;
UINT8 Len;
ASSERT ((Tcp != NULL) && (Option != NULL));
Option->Flag = 0;
TotalLen = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD));
if (TotalLen <= 0) {
return 0;
}
Head = (UINT8 *) (Tcp + 1);
//
// Fast process of the timestamp option.
//
if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) && (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {
Option->TSVal = TcpGetUint32 (Head + 4);
Option->TSEcr = TcpGetUint32 (Head + 8);
Option->Flag = TCP_OPTION_RCVD_TS;
return 0;
}
//
// Slow path to process the options.
//
Cur = 0;
while (Cur < TotalLen) {
Type = Head[Cur];
switch (Type) {
case TCP_OPTION_MSS:
Len = Head[Cur + 1];
if ((Len != TCP_OPTION_MSS_LEN) || (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {
return -1;
}
Option->Mss = TcpGetUint16 (&Head[Cur + 2]);
TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);
Cur += TCP_OPTION_MSS_LEN;
break;
case TCP_OPTION_WS:
Len = Head[Cur + 1];
if ((Len != TCP_OPTION_WS_LEN) || (TotalLen - Cur < TCP_OPTION_WS_LEN)) {
return -1;
}
Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]);
TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);
Cur += TCP_OPTION_WS_LEN;
break;
case TCP_OPTION_TS:
Len = Head[Cur + 1];
if ((Len != TCP_OPTION_TS_LEN) || (TotalLen - Cur < TCP_OPTION_TS_LEN)) {
return -1;
}
Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);
Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);
TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);
Cur += TCP_OPTION_TS_LEN;
break;
case TCP_OPTION_NOP:
Cur++;
break;
case TCP_OPTION_EOP:
Cur = TotalLen;
break;
default:
Len = Head[Cur + 1];
if ((TotalLen - Cur) < Len || Len < 2) {
return -1;
}
Cur = (UINT8) (Cur + Len);
break;
}
}
return 0;
}
/**
Check the segment against PAWS.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] TSVal The timestamp value.
@retval 1 The segment passed the PAWS check.
@retval 0 The segment failed to pass the PAWS check.
**/
UINT32
TcpPawsOK (
IN TCP_CB *Tcb,
IN UINT32 TSVal
)
{
//
// PAWS as defined in RFC1323, buggy...
//
if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&
TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)
) {
return 0;
}
return 1;
}

View File

@@ -0,0 +1,145 @@
/** @file
Tcp option's routine header file.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _TCP_OPTION_H_
#define _TCP_OPTION_H_
//
// Supported TCP option types and their length.
//
#define TCP_OPTION_EOP 0 ///< End Of oPtion
#define TCP_OPTION_NOP 1 ///< No-Option.
#define TCP_OPTION_MSS 2 ///< Maximum Segment Size
#define TCP_OPTION_WS 3 ///< Window scale
#define TCP_OPTION_TS 8 ///< Timestamp
#define TCP_OPTION_MSS_LEN 4 ///< Length of MSS option
#define TCP_OPTION_WS_LEN 3 ///< Length of window scale option
#define TCP_OPTION_TS_LEN 10 ///< Length of timestamp option
#define TCP_OPTION_WS_ALIGNED_LEN 4 ///< Length of window scale option, aligned
#define TCP_OPTION_TS_ALIGNED_LEN 12 ///< Length of timestamp option, aligned
//
// recommend format of timestamp window scale
// option for fast process.
//
#define TCP_OPTION_TS_FAST ((TCP_OPTION_NOP << 24) | \
(TCP_OPTION_NOP << 16) | \
(TCP_OPTION_TS << 8) | \
(TCP_OPTION_TS_LEN))
#define TCP_OPTION_WS_FAST ((TCP_OPTION_NOP << 24) | \
(TCP_OPTION_WS << 16) | \
(TCP_OPTION_WS_LEN << 8))
#define TCP_OPTION_MSS_FAST ((TCP_OPTION_MSS << 24) | (TCP_OPTION_MSS_LEN << 16))
//
// Other misc definations
//
#define TCP_OPTION_RCVD_MSS 0x01
#define TCP_OPTION_RCVD_WS 0x02
#define TCP_OPTION_RCVD_TS 0x04
#define TCP_OPTION_MAX_WS 14 ///< Maxium window scale value
#define TCP_OPTION_MAX_WIN 0xffff ///< Max window size in TCP header
///
/// The structure to store the parse option value.
/// ParseOption only parses the options, doesn't process them.
///
typedef struct _TCP_OPTION {
UINT8 Flag; ///< Flag such as TCP_OPTION_RCVD_MSS
UINT8 WndScale; ///< The WndScale received
UINT16 Mss; ///< The Mss received
UINT32 TSVal; ///< The TSVal field in a timestamp option
UINT32 TSEcr; ///< The TSEcr field in a timestamp option
} TCP_OPTION;
/**
Compute the window scale value according to the given buffer size.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@return The scale value.
**/
UINT8
TcpComputeScale (
IN TCP_CB *Tcb
);
/**
Build the TCP option in three-way handshake.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the buffer to store the options.
@return The total length of the TCP option field.
**/
UINT16
TcpSynBuildOption (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
);
/**
Build the TCP option in synchronized states.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Nbuf Pointer to the buffer to store the options.
@return The total length of the TCP option field.
**/
UINT16
TcpBuildOption (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
);
/**
Parse the supported options.
@param[in] Tcp Pointer to the TCP_CB of this TCP instance.
@param[in, out] Option Pointer to the TCP_OPTION used to store the
successfully pasrsed options.
@retval 0 The options successfully pasrsed.
@retval -1 Ilegal option was found.
**/
INTN
TcpParseOption (
IN TCP_HEAD *Tcp,
IN OUT TCP_OPTION *Option
);
/**
Check the segment against PAWS.
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] TSVal The timestamp value.
@retval 1 The segment passed the PAWS check.
@retval 0 The segment failed to pass the PAWS check.
**/
UINT32
TcpPawsOK (
IN TCP_CB *Tcb,
IN UINT32 TSVal
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,342 @@
/** @file
TCP protocol header file.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _TCP_PROTO_H_
#define _TCP_PROTO_H_
///
/// Tcp states don't change their order. It is used as an
/// index to mTcpOutFlag and other macros.
///
#define TCP_CLOSED 0
#define TCP_LISTEN 1
#define TCP_SYN_SENT 2
#define TCP_SYN_RCVD 3
#define TCP_ESTABLISHED 4
#define TCP_FIN_WAIT_1 5
#define TCP_FIN_WAIT_2 6
#define TCP_CLOSING 7
#define TCP_TIME_WAIT 8
#define TCP_CLOSE_WAIT 9
#define TCP_LAST_ACK 10
///
/// Flags in the TCP header
///
#define TCP_FLG_FIN 0x01
#define TCP_FLG_SYN 0x02
#define TCP_FLG_RST 0x04
#define TCP_FLG_PSH 0x08
#define TCP_FLG_ACK 0x10
#define TCP_FLG_URG 0x20
//
// mask for all the flags
//
#define TCP_FLG_FLAG 0x3F
#define TCP_CONNECT_REFUSED (-1) ///< TCP error status
#define TCP_CONNECT_RESET (-2) ///< TCP error status
#define TCP_CONNECT_CLOSED (-3) ///< TCP error status
//
// Current congestion status as suggested by RFC3782.
//
#define TCP_CONGEST_RECOVER 1 ///< During the NewReno fast recovery.
#define TCP_CONGEST_LOSS 2 ///< Retxmit because of retxmit time out.
#define TCP_CONGEST_OPEN 3 ///< TCP is opening its congestion window.
//
// TCP control flags
//
#define TCP_CTRL_NO_NAGLE 0x0001 ///< Disable Nagle algorithm
#define TCP_CTRL_NO_KEEPALIVE 0x0002 ///< Disable keepalive timer.
#define TCP_CTRL_NO_WS 0x0004 ///< Disable window scale option.
#define TCP_CTRL_RCVD_WS 0x0008 ///< Received a wnd scale option in syn.
#define TCP_CTRL_NO_TS 0x0010 ///< Disable Timestamp option.
#define TCP_CTRL_RCVD_TS 0x0020 ///< Received a Timestamp option in syn.
#define TCP_CTRL_SND_TS 0x0040 ///< Send Timestamp option to remote.
#define TCP_CTRL_SND_URG 0x0080 ///< In urgent send mode.
#define TCP_CTRL_RCVD_URG 0x0100 ///< In urgent receive mode.
#define TCP_CTRL_SND_PSH 0x0200 ///< In PUSH send mode.
#define TCP_CTRL_FIN_SENT 0x0400 ///< FIN is sent.
#define TCP_CTRL_FIN_ACKED 0x0800 ///< FIN is ACKed.
#define TCP_CTRL_TIMER_ON 0x1000 ///< At least one of the timer is on.
#define TCP_CTRL_RTT_ON 0x2000 ///< The RTT measurement is on.
#define TCP_CTRL_ACK_NOW 0x4000 ///< Send the ACK now, don't delay.
//
// Timer related values
//
#define TCP_TIMER_CONNECT 0 ///< Connection establishment timer.
#define TCP_TIMER_REXMIT 1 ///< Retransmit timer.
#define TCP_TIMER_PROBE 2 ///< Window probe timer.
#define TCP_TIMER_KEEPALIVE 3 ///< Keepalive timer.
#define TCP_TIMER_FINWAIT2 4 ///< FIN_WAIT_2 timer.
#define TCP_TIMER_2MSL 5 ///< TIME_WAIT timer.
#define TCP_TIMER_NUMBER 6 ///< The total number of the TCP timer.
#define TCP_TICK 200 ///< Every TCP tick is 200ms.
#define TCP_TICK_HZ 5 ///< The frequence of TCP tick.
#define TCP_RTT_SHIFT 3 ///< SRTT & RTTVAR scaled by 8.
#define TCP_RTO_MIN TCP_TICK_HZ ///< The minium value of RTO.
#define TCP_RTO_MAX (TCP_TICK_HZ * 60) ///< The maxium value of RTO.
#define TCP_FOLD_RTT 4 ///< Timeout threshod to fold RTT.
//
// Default values for some timers
//
#define TCP_MAX_LOSS 12 ///< Default max times to retxmit.
#define TCP_KEEPALIVE_IDLE_MIN (TCP_TICK_HZ * 60 * 60 * 2) ///< First keepalive.
#define TCP_KEEPALIVE_PERIOD (TCP_TICK_HZ * 60)
#define TCP_MAX_KEEPALIVE 8
#define TCP_FIN_WAIT2_TIME (2 * TCP_TICK_HZ)
#define TCP_TIME_WAIT_TIME (2 * TCP_TICK_HZ)
#define TCP_PAWS_24DAY (24 * 24 * 60 * 60 * TCP_TICK_HZ)
#define TCP_CONNECT_TIME (75 * TCP_TICK_HZ)
//
// The header space to be reserved before TCP data to accomodate :
// 60byte IP head + 60byte TCP head + link layer head
//
#define TCP_MAX_HEAD 192
//
// Value ranges for some control option
//
#define TCP_RCV_BUF_SIZE (2 * 1024 * 1024)
#define TCP_RCV_BUF_SIZE_MIN (8 * 1024)
#define TCP_SND_BUF_SIZE (2 * 1024 * 1024)
#define TCP_SND_BUF_SIZE_MIN (8 * 1024)
#define TCP_BACKLOG 10
#define TCP_BACKLOG_MIN 5
#define TCP_MAX_LOSS_MIN 6
#define TCP_CONNECT_TIME_MIN (60 * TCP_TICK_HZ)
#define TCP_MAX_KEEPALIVE_MIN 4
#define TCP_KEEPALIVE_IDLE_MAX (TCP_TICK_HZ * 60 * 60 * 4)
#define TCP_KEEPALIVE_PERIOD_MIN (TCP_TICK_HZ * 30)
#define TCP_FIN_WAIT2_TIME_MAX (4 * TCP_TICK_HZ)
#define TCP_TIME_WAIT_TIME_MAX (60 * TCP_TICK_HZ)
///
/// TCP_CONNECTED: both ends have synchronized their ISN.
///
#define TCP_CONNECTED(state) ((state) > TCP_SYN_RCVD)
#define TCP_FIN_RCVD(State) \
( \
((State) == TCP_CLOSE_WAIT) || \
((State) == TCP_LAST_ACK) || \
((State) == TCP_CLOSING) || \
((State) == TCP_TIME_WAIT) \
)
#define TCP_LOCAL_CLOSED(State) \
( \
((State) == TCP_FIN_WAIT_1) || \
((State) == TCP_FIN_WAIT_2) || \
((State) == TCP_CLOSING) || \
((State) == TCP_TIME_WAIT) || \
((State) == TCP_LAST_ACK) \
)
//
// Get the TCP_SEG point from a net buffer's ProtoData.
//
#define TCPSEG_NETBUF(NBuf) ((TCP_SEG *) ((NBuf)->ProtoData))
//
// Macros to compare sequence no
//
#define TCP_SEQ_LT(SeqA, SeqB) ((INT32) ((SeqA) - (SeqB)) < 0)
#define TCP_SEQ_LEQ(SeqA, SeqB) ((INT32) ((SeqA) - (SeqB)) <= 0)
#define TCP_SEQ_GT(SeqA, SeqB) ((INT32) ((SeqB) - (SeqA)) < 0)
#define TCP_SEQ_GEQ(SeqA, SeqB) ((INT32) ((SeqB) - (SeqA)) <= 0)
//
// TCP_SEQ_BETWEEN return whether b <= m <= e
//
#define TCP_SEQ_BETWEEN(b, m, e) ((e) - (b) >= (m) - (b))
//
// TCP_SUB_SEQ returns Seq1 - Seq2. Make sure Seq1 >= Seq2
//
#define TCP_SUB_SEQ(Seq1, Seq2) ((UINT32) ((Seq1) - (Seq2)))
//
// Check whether Flag is on
//
#define TCP_FLG_ON(Value, Flag) ((BOOLEAN) (((Value) & (Flag)) != 0))
//
// Set and Clear operation on a Flag
//
#define TCP_SET_FLG(Value, Flag) ((Value) |= (Flag))
#define TCP_CLEAR_FLG(Value, Flag) ((Value) &= ~(Flag))
//
// Test whether two peers are equal
//
#define TCP_PEER_EQUAL(Pa, Pb, Ver) \
(((Pa)->Port == (Pb)->Port) && TcpIsIpEqual(&((Pa)->Ip), &((Pb)->Ip), Ver))
//
// Test whether Pa matches Pb, or Pa is more specific
// than pb. Zero means wildcard.
//
#define TCP_PEER_MATCH(Pa, Pb, Ver) \
( \
(((Pb)->Port == 0) || ((Pb)->Port == (Pa)->Port)) && \
(TcpIsIpZero (&((Pb)->Ip), Ver) || TcpIsIpEqual (&((Pb)->Ip), &((Pa)->Ip), Ver)) \
)
#define TCP_TIMER_ON(Flag, Timer) ((Flag) & (1 << (Timer)))
#define TCP_SET_TIMER(Flag, Timer) ((Flag) = (UINT16) ((Flag) | (1 << (Timer))))
#define TCP_CLEAR_TIMER(Flag, Timer) ((Flag) = (UINT16) ((Flag) & (~(1 << (Timer)))))
#define TCP_TIME_LT(Ta, Tb) ((INT32) ((Ta) - (Tb)) < 0)
#define TCP_TIME_LEQ(Ta, Tb) ((INT32) ((Ta) - (Tb)) <= 0)
#define TCP_SUB_TIME(Ta, Tb) ((UINT32) ((Ta) - (Tb)))
#define TCP_MAX_WIN 0xFFFFU
///
/// TCP segmentation data.
///
typedef struct _TCP_SEG {
TCP_SEQNO Seq; ///< Starting sequence number.
TCP_SEQNO End; ///< The sequence of the last byte + 1, include SYN/FIN. End-Seq = SEG.LEN.
TCP_SEQNO Ack; ///< ACK field in the segment.
UINT8 Flag; ///< TCP header flags.
UINT16 Urg; ///< Valid if URG flag is set.
UINT32 Wnd; ///< TCP window size field.
} TCP_SEG;
///
/// Network endpoint, IP plus Port structure.
///
typedef struct _TCP_PEER {
EFI_IP_ADDRESS Ip; ///< IP address, in network byte order.
TCP_PORTNO Port; ///< Port number, in network byte order.
} TCP_PEER;
typedef struct _TCP_CONTROL_BLOCK TCP_CB;
///
/// TCP control block: it includes various states.
///
struct _TCP_CONTROL_BLOCK {
LIST_ENTRY List; ///< Back and forward link entry
TCP_CB *Parent; ///< The parent TCP_CB structure
SOCKET *Sk; ///< The socket it controled.
TCP_PEER LocalEnd; ///< Local endpoint.
TCP_PEER RemoteEnd;///< Remote endpoint.
LIST_ENTRY SndQue; ///< Retxmission queue.
LIST_ENTRY RcvQue; ///< Reassemble queue.
UINT32 CtrlFlag; ///< Control flags, such as NO_NAGLE.
INT32 Error; ///< Soft error status, such as TCP_CONNECT_RESET.
//
// RFC793 and RFC1122 defined variables
//
UINT8 State; ///< TCP state, such as SYN_SENT, LISTEN.
UINT8 DelayedAck; ///< Number of delayed ACKs.
UINT16 HeadSum; ///< Checksum of the fixed parts of pesudo
///< header: Src IP, Dst IP, 0, Protocol,
///< do not include the TCP length.
TCP_SEQNO Iss; ///< Initial Sending Sequence.
TCP_SEQNO SndUna; ///< First unacknowledged data.
TCP_SEQNO SndNxt; ///< Next data sequence to send.
TCP_SEQNO SndPsh; ///< Send PUSH point.
TCP_SEQNO SndUp; ///< Send urgent point.
UINT32 SndWnd; ///< Window advertised by the remote peer.
UINT32 SndWndMax; ///< Max send window advertised by the peer.
TCP_SEQNO SndWl1; ///< Seq number used for last window update.
TCP_SEQNO SndWl2; ///< Ack no of last window update.
UINT16 SndMss; ///< Max send segment size.
TCP_SEQNO RcvNxt; ///< Next sequence no to receive.
UINT32 RcvWnd; ///< Window advertised by the local peer.
TCP_SEQNO RcvWl2; ///< The RcvNxt (or ACK) of last window update.
///< It is necessary because of delayed ACK.
TCP_SEQNO RcvUp; ///< Urgent point;
TCP_SEQNO Irs; ///< Initial Receiving Sequence.
UINT16 RcvMss; ///< Max receive segment size.
UINT16 EnabledTimer; ///< Which timer is currently enabled.
UINT32 Timer[TCP_TIMER_NUMBER]; ///< When the timer will expire.
INT32 NextExpire; ///< Countdown offset for the nearest timer.
UINT32 Idle; ///< How long the connection is in idle.
UINT32 ProbeTime; ///< The time out value for current window prober.
BOOLEAN ProbeTimerOn;///< If TRUE, the probe time is on.
//
// RFC1323 defined variables, about window scale,
// timestamp and PAWS
//
UINT8 SndWndScale; ///< Wndscale received from the peer.
UINT8 RcvWndScale; ///< Wndscale used to scale local buffer.
UINT32 TsRecent; ///< TsRecent to echo to the remote peer.
UINT32 TsRecentAge; ///< When this TsRecent is updated.
//
// RFC2988 defined variables. about RTT measurement
//
TCP_SEQNO RttSeq; ///< The seq of measured segment now.
UINT32 RttMeasure; ///< Currently measured RTT in heartbeats.
UINT32 SRtt; ///< Smoothed RTT, scaled by 8.
UINT32 RttVar; ///< RTT variance, scaled by 8.
UINT32 Rto; ///< Current RTO, not scaled.
//
// RFC2581, and 3782 variables.
// Congestion control + NewReno fast recovery.
//
UINT32 CWnd; ///< Sender's congestion window.
UINT32 Ssthresh; ///< Slow start threshold.
TCP_SEQNO Recover; ///< Recover point for NewReno.
UINT16 DupAck; ///< Number of duplicate ACKs.
UINT8 CongestState; ///< The current congestion state(RFC3782).
UINT8 LossTimes; ///< Number of retxmit timeouts in a row.
TCP_SEQNO LossRecover; ///< Recover point for retxmit.
//
// configuration parameters, for EFI_TCP4_PROTOCOL specification
//
UINT32 KeepAliveIdle; ///< Idle time before sending first probe.
UINT32 KeepAlivePeriod; ///< Interval for subsequent keep alive probe.
UINT8 MaxKeepAlive; ///< Maxium keep alive probe times.
UINT8 KeepAliveProbes; ///< The number of keep alive probe.
UINT16 MaxRexmit; ///< The maxium number of retxmit before abort.
UINT32 FinWait2Timeout; ///< The FIN_WAIT_2 timeout.
UINT32 TimeWaitTimeout; ///< The TIME_WAIT timeout.
UINT32 ConnectTimeout; ///< The connect establishment timeout.
//
// configuration for tcp provided by user
//
BOOLEAN UseDefaultAddr;
UINT8 Tos;
UINT8 Ttl;
EFI_IPv4_ADDRESS SubnetMask;
IP_IO_IP_INFO *IpInfo; ///< Pointer reference to Ip used to send pkt
UINT32 Tick; ///< 1 tick = 200ms
};
#endif

View File

@@ -0,0 +1,593 @@
/** @file
TCP timer related functions.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
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 "TcpMain.h"
UINT32 mTcpTick = 1000;
/**
Connect timeout handler.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpConnectTimeout (
IN OUT TCP_CB *Tcb
);
/**
Timeout handler for TCP retransmission timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpRexmitTimeout (
IN OUT TCP_CB *Tcb
);
/**
Timeout handler for window probe timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpProbeTimeout (
IN OUT TCP_CB *Tcb
);
/**
Timeout handler for keepalive timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpKeepaliveTimeout (
IN OUT TCP_CB *Tcb
);
/**
Timeout handler for FIN_WAIT_2 timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpFinwait2Timeout (
IN OUT TCP_CB *Tcb
);
/**
Timeout handler for 2MSL timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
Tcp2MSLTimeout (
IN OUT TCP_CB *Tcb
);
TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {
TcpConnectTimeout,
TcpRexmitTimeout,
TcpProbeTimeout,
TcpKeepaliveTimeout,
TcpFinwait2Timeout,
Tcp2MSLTimeout,
};
/**
Close the TCP connection.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpClose (
IN OUT TCP_CB *Tcb
)
{
NetbufFreeList (&Tcb->SndQue);
NetbufFreeList (&Tcb->RcvQue);
TcpSetState (Tcb, TCP_CLOSED);
}
/**
Backoff the RTO.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpBackoffRto (
IN OUT TCP_CB *Tcb
)
{
//
// Fold the RTT estimate if too many times, the estimate
// may be wrong, fold it. So the next time a valid
// measurement is sampled, we can start fresh.
//
if ((Tcb->LossTimes >= TCP_FOLD_RTT) && (Tcb->SRtt != 0)) {
Tcb->RttVar += Tcb->SRtt >> 2;
Tcb->SRtt = 0;
}
Tcb->Rto <<= 1;
if (Tcb->Rto < TCP_RTO_MIN) {
Tcb->Rto = TCP_RTO_MIN;
} else if (Tcb->Rto > TCP_RTO_MAX) {
Tcb->Rto = TCP_RTO_MAX;
}
}
/**
Connect timeout handler.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpConnectTimeout (
IN OUT TCP_CB *Tcb
)
{
if (!TCP_CONNECTED (Tcb->State)) {
DEBUG (
(EFI_D_ERROR,
"TcpConnectTimeout: connection closed because conenction timer timeout for TCB %p\n",
Tcb)
);
if (EFI_ABORTED == Tcb->Sk->SockError) {
SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
}
if (TCP_SYN_RCVD == Tcb->State) {
DEBUG (
(EFI_D_WARN,
"TcpConnectTimeout: send reset because connection timer timeout for TCB %p\n",
Tcb)
);
TcpResetConnection (Tcb);
}
TcpClose (Tcb);
}
}
/**
Timeout handler for TCP retransmission timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpRexmitTimeout (
IN OUT TCP_CB *Tcb
)
{
UINT32 FlightSize;
DEBUG (
(EFI_D_WARN,
"TcpRexmitTimeout: transmission timeout for TCB %p\n",
Tcb)
);
//
// Set the congestion window. FlightSize is the
// amount of data that has been sent but not
// yet ACKed.
//
FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);
Tcb->Ssthresh = MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);
Tcb->CWnd = Tcb->SndMss;
Tcb->LossRecover = Tcb->SndNxt;
Tcb->LossTimes++;
if ((Tcb->LossTimes > Tcb->MaxRexmit) && !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {
DEBUG (
(EFI_D_ERROR,
"TcpRexmitTimeout: connection closed because too many timeouts for TCB %p\n",
Tcb)
);
if (EFI_ABORTED == Tcb->Sk->SockError) {
SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
}
TcpClose (Tcb);
return ;
}
TcpBackoffRto (Tcb);
TcpRetransmit (Tcb, Tcb->SndUna);
TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
Tcb->CongestState = TCP_CONGEST_LOSS;
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
}
/**
Timeout handler for window probe timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpProbeTimeout (
IN OUT TCP_CB *Tcb
)
{
//
// This is the timer for sender's SWSA. RFC1122 requires
// a timer set for sender's SWSA, and suggest combine it
// with window probe timer. If data is sent, don't set
// the probe timer, since retransmit timer is on.
//
if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {
ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT) != 0);
Tcb->ProbeTimerOn = FALSE;
return ;
}
TcpSendZeroProbe (Tcb);
TcpSetProbeTimer (Tcb);
}
/**
Timeout handler for keepalive timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpKeepaliveTimeout (
IN OUT TCP_CB *Tcb
)
{
Tcb->KeepAliveProbes++;
//
// Too many Keep-alive probes, drop the connection
//
if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {
if (EFI_ABORTED == Tcb->Sk->SockError) {
SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);
}
TcpClose (Tcb);
return ;
}
TcpSendZeroProbe (Tcb);
TcpSetKeepaliveTimer (Tcb);
}
/**
Timeout handler for FIN_WAIT_2 timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpFinwait2Timeout (
IN OUT TCP_CB *Tcb
)
{
DEBUG (
(EFI_D_WARN,
"TcpFinwait2Timeout: connection closed because FIN_WAIT2 timer timeouts for TCB %p\n",
Tcb)
);
TcpClose (Tcb);
}
/**
Timeout handler for 2MSL timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
Tcp2MSLTimeout (
IN OUT TCP_CB *Tcb
)
{
DEBUG (
(EFI_D_WARN,
"Tcp2MSLTimeout: connection closed because TIME_WAIT timer timeouts for TCB %p\n",
Tcb)
);
TcpClose (Tcb);
}
/**
Update the timer status and the next expire time according to the timers
to expire in a specific future time slot.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpUpdateTimer (
IN OUT TCP_CB *Tcb
)
{
UINT16 Index;
//
// Don't use a too large value to init NextExpire
// since mTcpTick wraps around as sequence no does.
//
Tcb->NextExpire = TCP_EXPIRE_TIME;
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&
TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)
) {
Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);
}
}
}
/**
Enable a TCP timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Timer The index of the timer to be enabled.
@param[in] TimeOut The timeout value of this timer.
**/
VOID
TcpSetTimer (
IN OUT TCP_CB *Tcb,
IN UINT16 Timer,
IN UINT32 TimeOut
)
{
TCP_SET_TIMER (Tcb->EnabledTimer, Timer);
Tcb->Timer[Timer] = mTcpTick + TimeOut;
TcpUpdateTimer (Tcb);
}
/**
Clear one TCP timer.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
@param[in] Timer The index of the timer to be cleared.
**/
VOID
TcpClearTimer (
IN OUT TCP_CB *Tcb,
IN UINT16 Timer
)
{
TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);
TcpUpdateTimer (Tcb);
}
/**
Clear all TCP timers.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpClearAllTimer (
IN OUT TCP_CB *Tcb
)
{
Tcb->EnabledTimer = 0;
TcpUpdateTimer (Tcb);
}
/**
Enable the window prober timer and set the timeout value.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpSetProbeTimer (
IN OUT TCP_CB *Tcb
)
{
if (!Tcb->ProbeTimerOn) {
Tcb->ProbeTime = Tcb->Rto;
Tcb->ProbeTimerOn = TRUE;
} else {
Tcb->ProbeTime <<= 1;
}
if (Tcb->ProbeTime < TCP_RTO_MIN) {
Tcb->ProbeTime = TCP_RTO_MIN;
} else if (Tcb->ProbeTime > TCP_RTO_MAX) {
Tcb->ProbeTime = TCP_RTO_MAX;
}
TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);
}
/**
Enable the keepalive timer and set the timeout value.
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.
**/
VOID
TcpSetKeepaliveTimer (
IN OUT TCP_CB *Tcb
)
{
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {
return ;
}
//
// Set the timer to KeepAliveIdle if either
// 1. the keepalive timer is off
// 2. The keepalive timer is on, but the idle
// is less than KeepAliveIdle, that means the
// connection is alive since our last probe.
//
if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||
(Tcb->Idle < Tcb->KeepAliveIdle)
) {
TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);
Tcb->KeepAliveProbes = 0;
} else {
TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);
}
}
/**
Heart beat timer handler.
@param[in] Context Context of the timer event, ignored.
**/
VOID
EFIAPI
TcpTickingDpc (
IN VOID *Context
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
TCP_CB *Tcb;
INT16 Index;
mTcpTick++;
mTcpGlobalIss += TCP_ISS_INCREMENT_2;
//
// Don't use LIST_FOR_EACH, which isn't delete safe.
//
for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {
Next = Entry->ForwardLink;
Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
if (Tcb->State == TCP_CLOSED) {
continue;
}
//
// The connection is doing RTT measurement.
//
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
Tcb->RttMeasure++;
}
Tcb->Idle++;
if (Tcb->DelayedAck != 0) {
TcpSendAck (Tcb);
}
if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick > 0) {
Tcb->Tick--;
}
//
// No timer is active or no timer expired
//
if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) || ((--Tcb->NextExpire) > 0)) {
continue;
}
//
// Call the timeout handler for each expired timer.
//
for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {
if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {
//
// disable the timer before calling the handler
// in case the handler enables it again.
//
TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);
mTcpTimerHandler[Index](Tcb);
//
// The Tcb may have been deleted by the timer, or
// no other timer is set.
//
if ((Next->BackLink != Entry) || (Tcb->EnabledTimer == 0)) {
break;
}
}
}
//
// If the Tcb still exist or some timer is set, update the timer
//
if (Index == TCP_TIMER_NUMBER) {
TcpUpdateTimer (Tcb);
}
}
}
/**
Heart beat timer handler, queues the DPC at TPL_CALLBACK.
@param[in] Event Timer event signaled, ignored.
@param[in] Context Context of the timer event, ignored.
**/
VOID
EFIAPI
TcpTicking (
IN EFI_EVENT Event,
IN VOID *Context
)
{
QueueDpc (TPL_CALLBACK, TcpTickingDpc, Context);
}