summaryrefslogtreecommitdiff
path: root/StdLib/EfiSocketLib
diff options
context:
space:
mode:
authorlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2012-02-09 19:16:44 +0000
committerlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2012-02-09 19:16:44 +0000
commit3bdf9aae5f7f4c5f47fc8f807ae4409dfe3bdd58 (patch)
tree39701f4ccf22d6842122baa1a27d92ff8040375f /StdLib/EfiSocketLib
parent5709e4e290f80aaf5ed6f1c7a9e3654a14e4ceb9 (diff)
Merged socket development branch:
* Fixed bug report (Duane Voth: Python sockets test application not working) by starting the receive operations when a connection is established! * Increased performance by extending the idle loop into the network stack with the Poll call. * Added support for TCPv6 (SOCK_STREAM) and UDPv6 (SOCK_DGRAM). * Added support for getaddrinfo and getnameinfo calls. * Moved application PCD values into AppPkg Signed-off-by: lpleahy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13002 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'StdLib/EfiSocketLib')
-rw-r--r--StdLib/EfiSocketLib/EfiSocketLib.inf8
-rw-r--r--StdLib/EfiSocketLib/Ip4.c1
-rw-r--r--StdLib/EfiSocketLib/Socket.c103
-rw-r--r--StdLib/EfiSocketLib/Socket.h125
-rw-r--r--StdLib/EfiSocketLib/Tcp4.c1
-rw-r--r--StdLib/EfiSocketLib/Tcp6.c2329
-rw-r--r--StdLib/EfiSocketLib/Udp4.c1
-rw-r--r--StdLib/EfiSocketLib/Udp6.c1094
-rw-r--r--StdLib/EfiSocketLib/UseEfiSocketLib.c31
9 files changed, 3684 insertions, 9 deletions
diff --git a/StdLib/EfiSocketLib/EfiSocketLib.inf b/StdLib/EfiSocketLib/EfiSocketLib.inf
index df639527f6..5e6ff595a9 100644
--- a/StdLib/EfiSocketLib/EfiSocketLib.inf
+++ b/StdLib/EfiSocketLib/EfiSocketLib.inf
@@ -34,7 +34,9 @@
Service.c
Socket.c
Tcp4.c
+ Tcp6.c
Udp4.c
+ Udp6.c
UseEfiSocketLib.c
[Packages]
@@ -52,9 +54,15 @@
[Protocols]
gEfiIp4ProtocolGuid
gEfiIp4ServiceBindingProtocolGuid
+ gEfiIp6ProtocolGuid
+ gEfiIp6ServiceBindingProtocolGuid
gEfiTcp4ProtocolGuid
gEfiTcp4ServiceBindingProtocolGuid
+ gEfiTcp6ProtocolGuid
+ gEfiTcp6ServiceBindingProtocolGuid
gEfiUdp4ProtocolGuid
gEfiUdp4ServiceBindingProtocolGuid
+ gEfiUdp6ProtocolGuid
+ gEfiUdp6ServiceBindingProtocolGuid
gEfiSocketProtocolGuid
gEfiSocketServiceBindingProtocolGuid
diff --git a/StdLib/EfiSocketLib/Ip4.c b/StdLib/EfiSocketLib/Ip4.c
index 9f885e96bf..f295b4250e 100644
--- a/StdLib/EfiSocketLib/Ip4.c
+++ b/StdLib/EfiSocketLib/Ip4.c
@@ -383,6 +383,7 @@ EslIp4PortAllocate (
//
pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.IPv4->Configure;
pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Cancel;
+ pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.IPv4->Poll;
pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Receive;
pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Transmit;
diff --git a/StdLib/EfiSocketLib/Socket.c b/StdLib/EfiSocketLib/Socket.c
index 9c2d2f6844..1805fa629c 100644
--- a/StdLib/EfiSocketLib/Socket.c
+++ b/StdLib/EfiSocketLib/Socket.c
@@ -481,6 +481,14 @@ CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
4, // RX buffers
4, // TX buffers
4 }, // TX Oob buffers
+ { L"Tcp6",
+ &gEfiTcp6ServiceBindingProtocolGuid,
+ &gEfiTcp6ProtocolGuid,
+ &mEslTcp6ServiceGuid,
+ OFFSET_OF ( ESL_LAYER, pTcp6List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 4 }, // TX Oob buffers
{ L"Udp4",
&gEfiUdp4ServiceBindingProtocolGuid,
&gEfiUdp4ProtocolGuid,
@@ -488,6 +496,14 @@ CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
OFFSET_OF ( ESL_LAYER, pUdp4List ),
4, // RX buffers
4, // TX buffers
+ 0 }, // TX Oob buffers
+ { L"Udp6",
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ &gEfiUdp6ProtocolGuid,
+ &mEslUdp6ServiceGuid,
+ OFFSET_OF ( ESL_LAYER, pUdp6List ),
+ 4, // RX buffers
+ 4, // TX buffers
0 } // TX Oob buffers
};
@@ -516,11 +532,11 @@ CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
**/
CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
NULL, // 0
- NULL, // SOCK_STREAM
- NULL, // SOCK_DGRAM
+ &cEslTcp6Api, // SOCK_STREAM
+ &cEslUdp6Api, // SOCK_DGRAM
NULL, // SOCK_RAW
NULL, // SOCK_RDM
- NULL // SOCK_SEQPACKET
+ &cEslTcp6Api // SOCK_SEQPACKET
};
/**
@@ -603,6 +619,7 @@ EslSocket (
// Validate the domain value
//
if (( AF_INET != domain )
+ && ( AF_INET6 != domain )
&& ( AF_LOCAL != domain )) {
DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
"ERROR - Invalid domain value\r\n" ));
@@ -1789,6 +1806,11 @@ EslSocketConnect (
if ( EFI_NOT_READY != Status ) {
if ( !EFI_ERROR ( Status )) {
pSocket->State = SOCKET_STATE_CONNECTED;
+
+ //
+ // Start the receive operations
+ //
+ EslSocketRxStart ( pSocket->pPortList );
}
else {
pSocket->State = SOCKET_STATE_BOUND;
@@ -1980,7 +2002,8 @@ EslSocketGetLocalAddress (
//
// Verify the socket state
//
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ if (( SOCKET_STATE_CONNECTED == pSocket->State )
+ || ( SOCKET_STATE_LISTENING == pSocket->State )) {
//
// Verify the API
//
@@ -3096,7 +3119,7 @@ EslSocketPacketAllocate (
LengthInBytes,
(VOID **)&pPacket );
if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
+ DEBUG (( DebugFlags | DEBUG_POOL,
"0x%08x: Allocate pPacket, %d bytes\r\n",
pPacket,
LengthInBytes ));
@@ -3210,6 +3233,7 @@ EslSocketPoll (
short DetectedEvents;
ESL_SOCKET * pSocket;
EFI_STATUS Status;
+ EFI_TPL TplPrevious;
short ValidEvents;
DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
@@ -3248,6 +3272,22 @@ EslSocketPoll (
}
else {
//
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Increase the network performance by extending the
+ // polling (idle) loop down into the LAN driver
+ //
+ EslSocketRxPoll ( pSocket );
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ //
// Check for pending connections
//
if ( 0 != pSocket->FifoDepth ) {
@@ -4367,6 +4407,11 @@ EslSocketReceive (
//
if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
//
+ // Poll the network to increase performance
+ //
+ EslSocketRxPoll ( pSocket );
+
+ //
// Locate the port
//
pPort = pSocket->pPortList;
@@ -4848,6 +4893,49 @@ EslSocketRxComplete (
/**
+ Poll a socket for pending receive activity.
+
+ This routine is called at elivated TPL and extends the idle
+ loop which polls a socket down into the LAN driver layer to
+ determine if there is any receive activity.
+
+ The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
+ routines call this routine when there is nothing to do.
+
+ @param [in] pSocket Address of an ::EFI_SOCKET structure.
+
+ **/
+VOID
+EslSocketRxPoll (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ ESL_PORT * pPort;
+
+ DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));
+
+ //
+ // Increase the network performance by extending the
+ // polling (idle) loop down into the LAN driver
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Poll the LAN adapter
+ //
+ pPort->pfnRxPoll ( pPort->pProtocol.v );
+
+ //
+ // Locate the next LAN adapter
+ //
+ pPort = pPort->pLinkSocket;
+ }
+
+ DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));
+}
+
+
+/**
Start a receive operation
This routine posts a receive buffer to the network adapter.
@@ -5292,6 +5380,11 @@ EslSocketTransmit (
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
+ // Poll the network to increase performance
+ //
+ EslSocketRxPoll ( pSocket );
+
+ //
// Attempt to buffer the packet for transmission
//
Status = pSocket->pApi->pfnTransmit ( pSocket,
diff --git a/StdLib/EfiSocketLib/Socket.h b/StdLib/EfiSocketLib/Socket.h
index 50bb2d3efd..30b642000e 100644
--- a/StdLib/EfiSocketLib/Socket.h
+++ b/StdLib/EfiSocketLib/Socket.h
@@ -138,6 +138,26 @@ typedef struct
/**
+ Receive context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv6.
+**/
+typedef struct
+{
+ EFI_TCP6_RECEIVE_DATA RxData; ///< Receive operation description
+ UINT8 Buffer[ RX_PACKET_DATA ]; ///< Data buffer
+} ESL_TCP6_RX_DATA;
+
+
+/**
+ Transmit context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv6.
+**/
+typedef struct
+{
+ EFI_TCP6_TRANSMIT_DATA TxData; ///< Transmit operation description
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_TCP6_TX_DATA;
+
+
+/**
Receive context for SOCK_DGRAM sockets using UDPv4.
**/
typedef struct
@@ -160,6 +180,28 @@ typedef struct
/**
+ Receive context for SOCK_DGRAM sockets using UDPv6.
+**/
+typedef struct
+{
+ EFI_UDP6_SESSION_DATA Session; ///< Remote network address
+ EFI_UDP6_RECEIVE_DATA * pRxData; ///< Receive operation description
+} ESL_UDP6_RX_DATA;
+
+
+/**
+ Transmit context for SOCK_DGRAM sockets using UDPv6.
+**/
+typedef struct
+{
+ EFI_UDP6_SESSION_DATA Session; ///< Remote network address
+ EFI_UDP6_TRANSMIT_DATA TxData; ///< Transmit operation description
+ UINTN RetransmitCount; ///< Retransmit to handle ARP negotiation
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_UDP6_TX_DATA;
+
+
+/**
Network specific context for transmit and receive packets.
**/
typedef struct _ESL_PACKET {
@@ -172,8 +214,12 @@ typedef struct _ESL_PACKET {
ESL_IP4_TX_DATA Ip4Tx; ///< Transmit operation description
ESL_TCP4_RX_DATA Tcp4Rx; ///< Receive operation description
ESL_TCP4_TX_DATA Tcp4Tx; ///< Transmit operation description
+ ESL_TCP6_RX_DATA Tcp6Rx; ///< Receive operation description
+ ESL_TCP6_TX_DATA Tcp6Tx; ///< Transmit operation description
ESL_UDP4_RX_DATA Udp4Rx; ///< Receive operation description
ESL_UDP4_TX_DATA Udp4Tx; ///< Transmit operation description
+ ESL_UDP6_RX_DATA Udp6Rx; ///< Receive operation description
+ ESL_UDP6_TX_DATA Udp6Tx; ///< Transmit operation description
} Op; ///< Network specific context
} GCC_ESL_PACKET;
@@ -217,8 +263,12 @@ typedef struct _ESL_IO_MGMT {
EFI_IP4_COMPLETION_TOKEN Ip4Tx; ///< IP4 transmit token
EFI_TCP4_IO_TOKEN Tcp4Rx; ///< TCP4 receive token
EFI_TCP4_IO_TOKEN Tcp4Tx; ///< TCP4 transmit token
+ EFI_TCP6_IO_TOKEN Tcp6Rx; ///< TCP6 receive token
+ EFI_TCP6_IO_TOKEN Tcp6Tx; ///< TCP6 transmit token
EFI_UDP4_COMPLETION_TOKEN Udp4Rx; ///< UDP4 receive token
EFI_UDP4_COMPLETION_TOKEN Udp4Tx; ///< UDP4 transmit token
+ EFI_UDP6_COMPLETION_TOKEN Udp6Rx; ///< UDP6 receive token
+ EFI_UDP6_COMPLETION_TOKEN Udp6Tx; ///< UDP6 transmit token
} Token; ///< Completion token for the network operation
} GCC_IO_MGMT;
@@ -257,6 +307,26 @@ typedef struct {
} ESL_TCP4_CONTEXT;
/**
+ TCP6 context structure
+
+ The driver uses this structure to manage the TCP6 connections.
+**/
+typedef struct {
+ //
+ // TCP6 context
+ //
+ EFI_TCP6_CONFIG_DATA ConfigData; ///< TCP6 configuration data
+ EFI_TCP6_OPTION Option; ///< TCP6 port options
+
+ //
+ // Tokens
+ //
+ EFI_TCP6_LISTEN_TOKEN ListenToken; ///< Listen control
+ EFI_TCP6_CONNECTION_TOKEN ConnectToken; ///< Connection control
+ EFI_TCP6_CLOSE_TOKEN CloseToken; ///< Close control
+} ESL_TCP6_CONTEXT;
+
+/**
UDP4 context structure
The driver uses this structure to manage the UDP4 connections.
@@ -268,6 +338,18 @@ typedef struct {
EFI_UDP4_CONFIG_DATA ConfigData; ///< UDP4 configuration data
} ESL_UDP4_CONTEXT;
+/**
+ UDP6 context structure
+
+ The driver uses this structure to manage the UDP6 connections.
+**/
+typedef struct {
+ //
+ // UDP6 context
+ //
+ EFI_UDP6_CONFIG_DATA ConfigData; ///< UDP6 configuration data
+} ESL_UDP6_CONTEXT;
+
/**
Configure the network layer.
@@ -302,6 +384,21 @@ EFI_STATUS
);
/**
+ Poll the LAN adapter for receive packets.
+
+ @param [in] pProtocol Protocol structure address
+ @param [in] pToken Completion token address
+
+ @return Returns EFI_SUCCESS if the operation is successfully
+ started.
+**/
+typedef
+EFI_STATUS
+(* PFN_NET_POLL) (
+ IN VOID * pProtocol
+ );
+
+/**
Port control structure
The driver uses this structure to manager the socket's connection
@@ -353,6 +450,7 @@ typedef struct _ESL_PORT {
// Receive data management
//
PFN_NET_IO_START pfnRxCancel; ///< Cancel a receive on the network
+ PFN_NET_POLL pfnRxPoll; ///< Poll the LAN adapter for receive packets
PFN_NET_IO_START pfnRxStart; ///< Start a receive on the network
ESL_IO_MGMT * pRxActive; ///< Active receive operation queue
ESL_IO_MGMT * pRxFree; ///< Free structure queue
@@ -364,12 +462,16 @@ typedef struct _ESL_PORT {
VOID * v; ///< VOID pointer
EFI_IP4_PROTOCOL * IPv4; ///< IP4 protocol pointer
EFI_TCP4_PROTOCOL * TCPv4; ///< TCP4 protocol pointer
+ EFI_TCP6_PROTOCOL * TCPv6; ///< TCP6 protocol pointer
EFI_UDP4_PROTOCOL * UDPv4; ///< UDP4 protocol pointer
+ EFI_UDP6_PROTOCOL * UDPv6; ///< UDP6 protocol pointer
} pProtocol; ///< Protocol structure address
union {
ESL_IP4_CONTEXT Ip4; ///< IPv4 management data
ESL_TCP4_CONTEXT Tcp4; ///< TCPv4 management data
+ ESL_TCP6_CONTEXT Tcp6; ///< TCPv6 management data
ESL_UDP4_CONTEXT Udp4; ///< UDPv4 management data
+ ESL_UDP6_CONTEXT Udp6; ///< UDPv6 management data
} Context; ///< Network specific context
}GCC_ESL_PORT;
@@ -975,7 +1077,9 @@ typedef struct {
//
ESL_SERVICE * pIp4List; ///< List of Ip4 services
ESL_SERVICE * pTcp4List; ///< List of Tcp4 services
+ ESL_SERVICE * pTcp6List; ///< List of Tcp6 services
ESL_SERVICE * pUdp4List; ///< List of Udp4 services
+ ESL_SERVICE * pUdp6List; ///< List of Udp6 services
//
// Socket management
@@ -992,8 +1096,11 @@ typedef struct {
extern ESL_LAYER mEslLayer;
extern CONST ESL_PROTOCOL_API cEslIp4Api;
+extern CONST ESL_PROTOCOL_API cEslIp6Api;
extern CONST ESL_PROTOCOL_API cEslTcp4Api;
+extern CONST ESL_PROTOCOL_API cEslTcp6Api;
extern CONST ESL_PROTOCOL_API cEslUdp4Api;
+extern CONST ESL_PROTOCOL_API cEslUdp6Api;
extern CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding;
@@ -1424,6 +1531,24 @@ EslSocketRxComplete (
);
/**
+ Poll a socket for pending receive activity.
+
+ This routine is called at elivated TPL and extends the idle
+ loop which polls a socket down into the LAN driver layer to
+ determine if there is any receive activity.
+
+ The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
+ routines call this routine when there is nothing to do.
+
+ @param [in] pSocket Address of an ::EFI_SOCKET structure.
+
+ **/
+VOID
+EslSocketRxPoll (
+ IN ESL_SOCKET * pSocket
+ );
+
+/**
Start a receive operation
This routine posts a receive buffer to the network adapter.
diff --git a/StdLib/EfiSocketLib/Tcp4.c b/StdLib/EfiSocketLib/Tcp4.c
index ec03b96bc1..b3ed45a716 100644
--- a/StdLib/EfiSocketLib/Tcp4.c
+++ b/StdLib/EfiSocketLib/Tcp4.c
@@ -1307,6 +1307,7 @@ EslTcp4PortAllocate (
// pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
//
pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;
+ pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;
pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;
pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;
diff --git a/StdLib/EfiSocketLib/Tcp6.c b/StdLib/EfiSocketLib/Tcp6.c
new file mode 100644
index 0000000000..0ee9fb6a64
--- /dev/null
+++ b/StdLib/EfiSocketLib/Tcp6.c
@@ -0,0 +1,2329 @@
+/** @file
+ Implement the TCP6 driver support for the socket layer.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+ \section ConnectionManagement Connection Management
+
+ The ::EslTcp6Listen routine initially places the SOCK_STREAM or
+ SOCK_SEQPACKET socket into a listen state. When a remote machine
+ makes a connection to the socket, the TCPv6 network layer calls
+ ::EslTcp6ListenComplete to complete the connection processing.
+ EslTcp6ListenComplete manages the connections by placing them in
+ FIFO order in a queue to be serviced by the application. When the
+ number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
+ the new connection is closed. Eventually, the application indirectly
+ calls ::EslTcp6Accept to remove the next connection from the queue
+ and get the associated socket.
+
+**/
+
+#include "Socket.h"
+
+
+/**
+ Attempt to connect to a remote TCP port
+
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCPv6 network layer. It
+ configures the local TCPv6 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp6ConnectComplete routine gets called with the connection
+ status.
+
+ This routine is called by ::EslSocketConnect to initiate the TCPv6
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp6ConnectComplete.
+ This pair of routines walks through the list of local TCPv6
+ connection points until a connection to the remote system is
+ made.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval EFI_NOT_READY The connection is in progress, call this routine again.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslTcp6ConnectStart (
+ IN ESL_SOCKET * pSocket
+ );
+
+
+/**
+ Process the connection attempt
+
+ A system has initiated a connection attempt with a socket in the
+ listen state. Attempt to complete the connection.
+
+ The TCPv6 layer calls this routine when a connection is made to
+ the socket in the listen state. See the
+ \ref ConnectionManagement section.
+
+ @param [in] Event The listen completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslTcp6ListenComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ );
+
+
+/**
+ Accept a network connection.
+
+ This routine waits for a network connection to the socket and
+ returns the remote network address to the caller if requested.
+
+ This routine is called by ::EslSocketAccept to handle the TCPv6 protocol
+ specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
+ See the \ref ConnectionManagement section.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @param [in] pSockAddr Address of a buffer to receive the remote
+ network address.
+
+ @param [in, out] pSockAddrLength Length in bytes of the address buffer.
+ On output specifies the length of the
+ remote network address.
+
+ @retval EFI_SUCCESS Remote address is available
+ @retval Others Remote address not available
+
+ **/
+EFI_STATUS
+EslTcp6Accept (
+ IN ESL_SOCKET * pSocket,
+ IN struct sockaddr * pSockAddr,
+ IN OUT socklen_t * pSockAddrLength
+ )
+{
+ ESL_PORT * pPort;
+ struct sockaddr_in6 * pRemoteAddress;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Validate the socket length
+ //
+ pRemoteAddress = (struct sockaddr_in6 *) pSockAddr;
+ if (( NULL == pSockAddrLength )
+ || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {
+ //
+ // Invalid socket address
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ DEBUG (( DEBUG_ACCEPT,
+ "ERROR - Invalid address length\r\n" ));
+ }
+ else {
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Locate the address context
+ //
+ pPort = pSocket->pPortList;
+ pTcp6 = &pPort->Context.Tcp6;
+
+ //
+ // Fill-in the remote address structure
+ //
+ ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));
+ pRemoteAddress->sin6_len = sizeof ( *pRemoteAddress );
+ pRemoteAddress->sin6_family = AF_INET6;
+ pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
+ CopyMem ( &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
+ &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the remote connection completion event.
+
+ This routine handles the completion of a connection attempt. It
+ releases the port (TCPv6 adapter connection) in the case of an
+ error and start a connection attempt on the next port. If the
+ connection attempt was successful then this routine releases all
+ of the other ports.
+
+ This routine is called by the TCPv6 layer when a connect request
+ completes. It sets the ESL_SOCKET::bConnected flag to notify the
+ ::EslTcp6ConnectComplete routine that the connection is available.
+ The flag is set when the connection is established or no more ports
+ exist in the list. The connection status is passed via
+ ESL_SOCKET::ConnectStatus.
+
+ @param [in] Event The connect completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslTcp6ConnectComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ )
+{
+ BOOLEAN bRemoveFirstPort;
+ BOOLEAN bRemovePorts;
+ ESL_PORT * pNextPort;
+ ESL_SOCKET * pSocket;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the TCP context
+ //
+ pSocket = pPort->pSocket;
+ pTcp6 = &pPort->Context.Tcp6;
+
+ //
+ // Get the connection status
+ //
+ bRemoveFirstPort = FALSE;
+ bRemovePorts = FALSE;
+ Status = pTcp6->ConnectToken.CompletionToken.Status;
+ pSocket->ConnectStatus = Status;
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // The connection was successful
+ //
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
+ pTcp6->ConfigData.AccessPoint.RemotePort ));
+
+ //
+ // Remove the rest of the ports
+ //
+ bRemovePorts = TRUE;
+ }
+ else {
+ //
+ // The connection failed
+ //
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port connection to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d failed, Status: %r\r\n",
+ pPort,
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
+ pTcp6->ConfigData.AccessPoint.RemotePort,
+ Status ));
+
+ //
+ // Close the current port
+ //
+ Status = EslSocketPortClose ( pPort );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port closed\r\n",
+ pPort ));
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ }
+
+ //
+ // Try to connect using the next port
+ //
+ Status = EslTcp6ConnectStart ( pSocket );
+ if ( EFI_NOT_READY != Status ) {
+ pSocket->ConnectStatus = Status;
+ bRemoveFirstPort = TRUE;
+ }
+ }
+
+ //
+ // Remove the ports if necessary
+ //
+ if ( bRemoveFirstPort || bRemovePorts ) {
+ //
+ // Remove the first port if necessary
+ //
+ pPort = pSocket->pPortList;
+ if (( !bRemoveFirstPort ) && ( NULL != pPort )) {
+ pPort = pPort->pLinkSocket;
+ }
+
+ //
+ // Remove the rest of the list
+ //
+ while ( NULL != pPort ) {
+ pNextPort = pPort->pLinkSocket;
+ EslSocketPortClose ( pPort );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port closed\r\n",
+ pPort ));
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ }
+ pPort = pNextPort;
+ }
+
+ //
+ // Notify the poll routine
+ //
+ pSocket->bConnected = TRUE;
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Poll for completion of the connection attempt.
+
+ This routine polls the ESL_SOCKET::bConnected flag to determine
+ when the connection attempt is complete.
+
+ This routine is called from ::EslSocketConnect to determine when
+ the connection is complete. The ESL_SOCKET::bConnected flag is
+ set by ::EslTcp6ConnectComplete when the TCPv6 layer establishes
+ a connection or runs out of local network adapters. This routine
+ gets the connection status from ESL_SOCKET::ConnectStatus.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval EFI_NOT_READY The connection is in progress, call this routine again.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslTcp6ConnectPoll (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine if the connection is complete
+ //
+ if ( !pSocket->bConnected ) {
+ //
+ // Not connected
+ //
+ pSocket->errno = EAGAIN;
+ Status = EFI_NOT_READY;
+ }
+ else {
+ //
+ // The connection processing is complete
+ //
+ pSocket->bConnected = FALSE;
+
+ //
+ // Translate the connection status
+ //
+ Status = pSocket->ConnectStatus;
+ switch ( Status ) {
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_ABORTED:
+ pSocket->errno = ECONNREFUSED;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EINVAL;
+ break;
+
+ case EFI_NO_MAPPING:
+ case EFI_NO_RESPONSE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
+
+ case EFI_NO_MEDIA:
+ pSocket->errno = ENETDOWN;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOMEM;
+ break;
+
+ case EFI_SUCCESS:
+ pSocket->errno = 0;
+ pSocket->bConfigured = TRUE;
+ break;
+
+ case EFI_TIMEOUT:
+ pSocket->errno = ETIMEDOUT;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = ENOTSUP;
+ break;
+
+ case 0x80000069:
+ pSocket->errno = ECONNRESET;
+ break;
+ }
+ }
+
+ //
+ // Return the initialization status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Attempt to connect to a remote TCP port
+
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCPv6 network layer. It
+ configures the local TCPv6 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp6ConnectComplete routine gets called with the connection
+ status.
+
+ This routine is called by ::EslSocketConnect to initiate the TCPv6
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp6ConnectComplete.
+ This pair of routines walks through the list of local TCPv6
+ connection points until a connection to the remote system is
+ made.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval EFI_NOT_READY The connection is in progress, call this routine again.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslTcp6ConnectStart (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ ESL_PORT * pPort;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_TCP6_PROTOCOL * pTcp6Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine if any more local adapters are available
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Configure the port
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ pTcp6->ConfigData.AccessPoint.ActiveFlag = TRUE;
+ pTcp6->ConfigData.TrafficClass = 0;
+ pTcp6->ConfigData.HopLimit = 255;
+ pTcp6Protocol = pPort->pProtocol.TCPv6;
+ Status = pTcp6Protocol->Configure ( pTcp6Protocol,
+ &pTcp6->ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NO_MAPPING:
+ pSocket->errno = EAFNOSUPPORT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = EOPNOTSUPP;
+ break;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port configured\r\n",
+ pPort ));
+ pPort->bConfigured = TRUE;
+
+ //
+ // Attempt the connection to the remote system
+ //
+ Status = pTcp6Protocol->Connect ( pTcp6Protocol,
+ &pTcp6->ConnectToken );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Connection in progress
+ //
+ pSocket->errno = EINPROGRESS;
+ Status = EFI_NOT_READY;
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port attempting connection to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
+ pTcp6->ConfigData.AccessPoint.RemotePort ));
+ }
+ else {
+ //
+ // Connection error
+ //
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Port 0x%08x not connected, Status: %r\r\n",
+ pPort,
+ Status ));
+ //
+ // Determine the errno value
+ //
+ switch ( Status ) {
+ default:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_TIMEOUT:
+ pSocket->errno = ETIMEDOUT;
+ break;
+
+ case EFI_NETWORK_UNREACHABLE:
+ pSocket->errno = ENETDOWN;
+ break;
+
+ case EFI_HOST_UNREACHABLE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
+
+ case EFI_PORT_UNREACHABLE:
+ case EFI_PROTOCOL_UNREACHABLE:
+ case EFI_CONNECTION_REFUSED:
+ pSocket->errno = ECONNREFUSED;
+ break;
+
+ case EFI_CONNECTION_RESET:
+ pSocket->errno = ECONNRESET;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ //
+ // No more local adapters available
+ //
+ pSocket->errno = ENETUNREACH;
+ Status = EFI_NO_RESPONSE;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Establish the known port to listen for network connections.
+
+ This routine places the port into a state that enables connection
+ attempts.
+
+ This routine is called by ::EslSocketListen to handle the network
+ specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
+ sockets. See the \ref ConnectionManagement section.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS - Socket successfully created
+ @retval Other - Failed to enable the socket for listen
+
+**/
+EFI_STATUS
+EslTcp6Listen (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ ESL_PORT * pNextPort;
+ ESL_PORT * pPort;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_TCP6_PROTOCOL * pTcp6Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Use for/break instead of goto
+ //
+ for ( ; ; ) {
+ //
+ // Assume no ports are available
+ //
+ pSocket->errno = EOPNOTSUPP;
+ Status = EFI_NOT_READY;
+
+ //
+ // Walk the list of ports
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+
+ //
+ // Use for/break insteak of goto
+ //
+ for ( ; ; ) {
+ //
+ // Create the listen completion event
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)EslTcp6ListenComplete,
+ pPort,
+ &pTcp6->ListenToken.CompletionToken.Event );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
+ "ERROR - Failed to create the listen completion event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Created listen completion event\r\n",
+ pTcp6->ListenToken.CompletionToken.Event ));
+
+ //
+ // Configure the port
+ //
+ pTcp6Protocol = pPort->pProtocol.TCPv6;
+ Status = pTcp6Protocol->Configure ( pTcp6Protocol,
+ &pTcp6->ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_LISTEN,
+ "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NO_MAPPING:
+ pSocket->errno = EAFNOSUPPORT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = EOPNOTSUPP;
+ break;
+ }
+ break;
+ }
+ DEBUG (( DEBUG_LISTEN,
+ "0x%08x: Port configured\r\n",
+ pPort ));
+ pPort->bConfigured = TRUE;
+
+ //
+ // Start the listen operation on the port
+ //
+ Status = pTcp6Protocol->Accept ( pTcp6Protocol,
+ &pTcp6->ListenToken );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_LISTEN,
+ "ERROR - Failed Tcp6 accept, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NOT_STARTED:
+ pSocket->errno = ENETDOWN;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+ }
+ break;
+ }
+ DEBUG (( DEBUG_LISTEN,
+ "0x%08x: Listen pending on Port\r\n",
+ pPort ));
+
+ //
+ // Listen is pending on this port
+ //
+ break;
+ }
+
+ //
+ // Get the next port
+ //
+ pNextPort = pPort->pLinkSocket;
+
+ //
+ // Close the port upon error
+ //
+ if ( EFI_ERROR ( Status )) {
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
+ }
+
+ //
+ // Set the next port
+ //
+ pPort = pNextPort;
+ }
+
+ //
+ // Determine if any ports are in the listen state
+ //
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // No ports in the listen state
+ //
+ pSocket->MaxFifoDepth = 0;
+
+ //
+ // Return the last error detected
+ //
+ break;
+ }
+
+ //
+ // Mark the socket as configured
+ //
+ pSocket->bConfigured = TRUE;
+
+ //
+ // All done
+ //
+ DEBUG (( DEBUG_LISTEN,
+ "0x%08x: pSocket - Listen pending on socket\r\n",
+ pSocket ));
+ break;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the connection attempt
+
+ A system has initiated a connection attempt with a socket in the
+ listen state. Attempt to complete the connection.
+
+ The TCPv6 layer calls this routine when a connection is made to
+ the socket in the listen state. See the
+ \ref ConnectionManagement section.
+
+ @param [in] Event The listen completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslTcp6ListenComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ )
+{
+ EFI_HANDLE ChildHandle;
+ struct sockaddr_in6 LocalAddress;
+ EFI_TCP6_CONFIG_DATA * pConfigData;
+ ESL_LAYER * pLayer;
+ ESL_PORT * pNewPort;
+ ESL_SOCKET * pNewSocket;
+ ESL_SOCKET * pSocket;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_TCP6_PROTOCOL * pTcp6Protocol;
+ EFI_STATUS Status;
+ EFI_HANDLE TcpPortHandle;
+ EFI_STATUS TempStatus;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if this connection fits into the connection FIFO
+ //
+ pSocket = pPort->pSocket;
+ TcpPortHandle = pPort->Context.Tcp6.ListenToken.NewChildHandle;
+ if (( SOCKET_STATE_LISTENING == pSocket->State )
+ && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {
+ //
+ // Allocate a socket for this connection
+ //
+ ChildHandle = NULL;
+ pLayer = &mEslLayer;
+ Status = EslSocketAllocate ( &ChildHandle,
+ DEBUG_CONNECTION,
+ &pNewSocket );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Clone the socket parameters
+ //
+ pNewSocket->pApi = pSocket->pApi;
+ pNewSocket->Domain = pSocket->Domain;
+ pNewSocket->Protocol = pSocket->Protocol;
+ pNewSocket->Type = pSocket->Type;
+
+ //
+ // Build the local address
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ LocalAddress.sin6_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
+ LocalAddress.sin6_family = AF_INET6;
+ LocalAddress.sin6_port = 0;
+ CopyMem ( &LocalAddress.sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
+ &pTcp6->ConfigData.AccessPoint.StationAddress.Addr [ 0 ],
+ sizeof ( pTcp6->ConfigData.AccessPoint.StationAddress.Addr ));
+
+ //
+ // Allocate a port for this connection
+ // Note in this instance Configure may not be called with NULL!
+ //
+ Status = EslSocketPortAllocate ( pNewSocket,
+ pPort->pService,
+ TcpPortHandle,
+ (struct sockaddr *)&LocalAddress,
+ FALSE,
+ DEBUG_CONNECTION,
+ &pNewPort );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Restart the listen operation on the port
+ //
+ pTcp6Protocol = pPort->pProtocol.TCPv6;
+ Status = pTcp6Protocol->Accept ( pTcp6Protocol,
+ &pTcp6->ListenToken );
+
+ //
+ // Close the TCP port using SocketClose
+ //
+ TcpPortHandle = NULL;
+ pTcp6 = &pNewPort->Context.Tcp6;
+
+ //
+ // Check for an accept call error
+ //
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Get the port configuration
+ //
+ pNewPort->bConfigured = TRUE;
+ pConfigData = &pTcp6->ConfigData;
+ pConfigData->ControlOption = &pTcp6->Option;
+ pTcp6Protocol = pNewPort->pProtocol.TCPv6;
+ Status = pTcp6Protocol->GetModeData ( pTcp6Protocol,
+ NULL,
+ pConfigData,
+ NULL,
+ NULL,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Add the new socket to the connection FIFO
+ //
+ if ( NULL == pSocket->pFifoTail ) {
+ //
+ // First connection
+ //
+ pSocket->pFifoHead = pNewSocket;
+ }
+ else {
+ //
+ // Add to end of list.
+ //
+ pSocket->pFifoTail->pNextConnection = pNewSocket;
+ }
+ pSocket->pFifoTail = pNewSocket;
+ pSocket->FifoDepth += 1;
+
+ //
+ // Update the socket state
+ //
+ pNewSocket->State = SOCKET_STATE_IN_FIFO;
+
+ //
+ // Log the connection
+ //
+ DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
+ "0x%08x: Socket on port [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pNewSocket,
+ pConfigData->AccessPoint.StationAddress.Addr[0],
+ pConfigData->AccessPoint.StationAddress.Addr[1],
+ pConfigData->AccessPoint.StationAddress.Addr[2],
+ pConfigData->AccessPoint.StationAddress.Addr[3],
+ pConfigData->AccessPoint.StationAddress.Addr[4],
+ pConfigData->AccessPoint.StationAddress.Addr[5],
+ pConfigData->AccessPoint.StationAddress.Addr[6],
+ pConfigData->AccessPoint.StationAddress.Addr[7],
+ pConfigData->AccessPoint.StationAddress.Addr[8],
+ pConfigData->AccessPoint.StationAddress.Addr[9],
+ pConfigData->AccessPoint.StationAddress.Addr[10],
+ pConfigData->AccessPoint.StationAddress.Addr[11],
+ pConfigData->AccessPoint.StationAddress.Addr[12],
+ pConfigData->AccessPoint.StationAddress.Addr[13],
+ pConfigData->AccessPoint.StationAddress.Addr[14],
+ pConfigData->AccessPoint.StationAddress.Addr[15],
+ pConfigData->AccessPoint.StationPort,
+ pConfigData->AccessPoint.RemoteAddress.Addr[0],
+ pConfigData->AccessPoint.RemoteAddress.Addr[1],
+ pConfigData->AccessPoint.RemoteAddress.Addr[2],
+ pConfigData->AccessPoint.RemoteAddress.Addr[3],
+ pConfigData->AccessPoint.RemoteAddress.Addr[4],
+ pConfigData->AccessPoint.RemoteAddress.Addr[5],
+ pConfigData->AccessPoint.RemoteAddress.Addr[6],
+ pConfigData->AccessPoint.RemoteAddress.Addr[7],
+ pConfigData->AccessPoint.RemoteAddress.Addr[8],
+ pConfigData->AccessPoint.RemoteAddress.Addr[9],
+ pConfigData->AccessPoint.RemoteAddress.Addr[10],
+ pConfigData->AccessPoint.RemoteAddress.Addr[11],
+ pConfigData->AccessPoint.RemoteAddress.Addr[12],
+ pConfigData->AccessPoint.RemoteAddress.Addr[13],
+ pConfigData->AccessPoint.RemoteAddress.Addr[14],
+ pConfigData->AccessPoint.RemoteAddress.Addr[15],
+ pConfigData->AccessPoint.RemotePort ));
+ DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
+ "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
+ pSocket,
+ pNewSocket,
+ pSocket->FifoDepth ));
+
+ //
+ // Start the receive operation
+ //
+ EslSocketRxStart ( pNewPort );
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
+ "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
+ pNewPort,
+ Status ));
+ }
+ }
+ else {
+ //
+ // The listen failed on this port
+ //
+ DEBUG (( DEBUG_LISTEN | DEBUG_INFO,
+ "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+
+ //
+ // Close the listening port
+ //
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
+ }
+ }
+
+ //
+ // Done with the socket if necessary
+ //
+ if ( EFI_ERROR ( Status )) {
+ TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,
+ TRUE,
+ &pSocket->errno );
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
+ }
+ }
+ else {
+ DEBUG (( DEBUG_CONNECTION,
+ "0x%08x: Socket FIFO full, connection refused\r\n",
+ pSocket ));
+
+ //
+ // The FIFO is full or the socket is in the wrong state
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Close the connection if necessary
+ //
+ if (( EFI_ERROR ( Status ))
+ && ( NULL == TcpPortHandle )) {
+ //
+ // TODO: Finish this code path
+ // The new connection does not fit into the connection FIFO
+ //
+ // Process:
+ // Call close
+ // Release the resources
+
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Get the local socket address.
+
+ This routine returns the IPv6 address and TCP port number associated
+ with the local socket.
+
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pSockAddr Network address to receive the local system address
+
+**/
+VOID
+EslTcp6LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
+ )
+{
+ struct sockaddr_in6 * pLocalAddress;
+ ESL_TCP6_CONTEXT * pTcp6;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ pLocalAddress = (struct sockaddr_in6 *)pSockAddr;
+ pLocalAddress->sin6_family = AF_INET6;
+ pLocalAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.StationPort );
+ CopyMem ( &pLocalAddress->sin6_addr,
+ &pTcp6->ConfigData.AccessPoint.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin6_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the local port address.
+
+ This routine sets the local port address.
+
+ This support routine is called by ::EslSocketPortAllocate.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv6 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv6 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+
+ @param [in] bBindTest TRUE = run bind testing
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslTcp6LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
+ )
+{
+ EFI_TCP6_ACCESS_POINT * pAccessPoint;
+ CONST struct sockaddr_in6 * pIpAddress;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in6 *)pSockAddr;
+//
+// TODO: Fix the following check
+//
+/*
+ if ( INADDR_BROADCAST == pIpAddress->sin6_addr.s_addr ) {
+ //
+ // The local address must not be the broadcast address
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
+*/
+{
+ //
+ // Set the local address
+ //
+ pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint;
+ CopyMem ( &pAccessPoint->StationAddress.Addr[0],
+ &pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
+ sizeof ( pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ]));
+
+ //
+ // Validate the IP address
+ //
+ pAccessPoint->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Set the port number
+ //
+ pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin6_port );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local Tcp6 Address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pAccessPoint->StationAddress.Addr[0],
+ pAccessPoint->StationAddress.Addr[1],
+ pAccessPoint->StationAddress.Addr[2],
+ pAccessPoint->StationAddress.Addr[3],
+ pAccessPoint->StationAddress.Addr[4],
+ pAccessPoint->StationAddress.Addr[5],
+ pAccessPoint->StationAddress.Addr[6],
+ pAccessPoint->StationAddress.Addr[7],
+ pAccessPoint->StationAddress.Addr[8],
+ pAccessPoint->StationAddress.Addr[9],
+ pAccessPoint->StationAddress.Addr[10],
+ pAccessPoint->StationAddress.Addr[11],
+ pAccessPoint->StationAddress.Addr[12],
+ pAccessPoint->StationAddress.Addr[13],
+ pAccessPoint->StationAddress.Addr[14],
+ pAccessPoint->StationAddress.Addr[15],
+ pAccessPoint->StationPort ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
+
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
+
+**/
+VOID
+EslTcp6PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ DBG_ENTER ( );
+
+ //
+ // Account for the receive bytes
+ //
+ *pRxBytes -= pPacket->Op.Tcp6Rx.RxData.DataLength;
+ DBG_EXIT ( );
+}
+
+
+/**
+ Initialize the network specific portions of an ::ESL_PORT structure.
+
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
+
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the TCPv6 protocol.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslTcp6PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_TCP6_ACCESS_POINT * pAccessPoint;
+ ESL_SOCKET * pSocket;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Use for/break instead of goto
+ for ( ; ; ) {
+ //
+ // Allocate the close event
+ //
+ pSocket = pPort->pSocket;
+ pTcp6 = &pPort->Context.Tcp6;
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
+ pPort,
+ &pTcp6->CloseToken.CompletionToken.Event);
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the close event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
+ "0x%08x: Created close event\r\n",
+ pTcp6->CloseToken.CompletionToken.Event ));
+
+ //
+ // Allocate the connection event
+ //
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)EslTcp6ConnectComplete,
+ pPort,
+ &pTcp6->ConnectToken.CompletionToken.Event);
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the connect event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
+ "0x%08x: Created connect event\r\n",
+ pTcp6->ConnectToken.CompletionToken.Event ));
+
+ //
+ // Initialize the port
+ //
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp6Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Tx.CompletionToken.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP6_IO_TOKEN, Packet.TxData );
+
+ //
+ // Save the cancel, receive and transmit addresses
+ // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
+ //
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv6->Configure;
+ pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv6->Poll;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Transmit;
+
+ //
+ // Set the configuration flags
+ //
+ pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint;
+ pAccessPoint->ActiveFlag = FALSE;
+ pTcp6->ConfigData.TrafficClass = 0;
+ pTcp6->ConfigData.HopLimit = 255;
+ break;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Close a Tcp6 port.
+
+ This routine releases the network specific resources allocated by
+ ::EslTcp6PortAllocate.
+
+ This routine is called by ::EslSocketPortClose.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
+
+**/
+EFI_STATUS
+EslTcp6PortClose (
+ IN ESL_PORT * pPort
+ )
+{
+ UINTN DebugFlags;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the port in the socket list
+ //
+ Status = EFI_SUCCESS;
+ DebugFlags = pPort->DebugFlags;
+ pTcp6 = &pPort->Context.Tcp6;
+
+ //
+ // Done with the connect event
+ //
+ if ( NULL != pTcp6->ConnectToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( pTcp6->ConnectToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Closed connect event\r\n",
+ pTcp6->ConnectToken.CompletionToken.Event ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the connect event, Status: %r\r\n",
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the close event
+ //
+ if ( NULL != pTcp6->CloseToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( pTcp6->CloseToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Closed close event\r\n",
+ pTcp6->CloseToken.CompletionToken.Event ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the close event, Status: %r\r\n",
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the listen completion event
+ //
+ if ( NULL != pTcp6->ListenToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( pTcp6->ListenToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Closed listen completion event\r\n",
+ pTcp6->ListenToken.CompletionToken.Event ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the listen completion event, Status: %r\r\n",
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Perform the network specific close operation on the port.
+
+ This routine performs a cancel operations on the TCPv6 port to
+ shutdown the receive operations on the port.
+
+ This routine is called by the ::EslSocketPortCloseTxDone
+ routine after the port completes all of the transmission.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port is still closing
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslTcp6PortCloseOp (
+ IN ESL_PORT * pPort
+ )
+{
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_TCP6_PROTOCOL * pTcp6Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Close the configured port
+ //
+ Status = EFI_SUCCESS;
+ pTcp6 = &pPort->Context.Tcp6;
+ pTcp6Protocol = pPort->pProtocol.TCPv6;
+ pTcp6->CloseToken.AbortOnClose = pPort->bCloseNow;
+ Status = pTcp6Protocol->Close ( pTcp6Protocol,
+ &pTcp6->CloseToken );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port close started\r\n",
+ pPort ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Receive data from a network connection.
+
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
+ sockets.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
+
+ @return Returns the address of the next free byte in the buffer.
+
+ **/
+UINT8 *
+EslTcp6Receive (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ OUT size_t * pSkipBytes
+ )
+{
+ size_t DataLength;
+ struct sockaddr_in6 * pRemoteAddress;
+ ESL_TCP6_CONTEXT * pTcp6;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote system address if requested
+ //
+ if ( NULL != pAddress ) {
+ //
+ // Build the remote address
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
+ pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
+ pTcp6->ConfigData.AccessPoint.RemotePort ));
+ pRemoteAddress = (struct sockaddr_in6 *)pAddress;
+ CopyMem ( &pRemoteAddress->sin6_addr,
+ &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin6_addr ));
+ pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
+ }
+
+ //
+ // Determine the amount of received data
+ //
+ DataLength = pPacket->ValidBytes;
+ if ( BufferLength < DataLength ) {
+ DataLength = BufferLength;
+ }
+
+ //
+ // Move the data into the buffer
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
+ pPort,
+ pPacket,
+ pBuffer,
+ DataLength ));
+ CopyMem ( pBuffer, pPacket->pBuffer, DataLength );
+
+ //
+ // Determine if the data is being read
+ //
+ if ( *pbConsumePacket ) {
+ //
+ // Account for the bytes consumed
+ //
+ pPacket->pBuffer += DataLength;
+ pPacket->ValidBytes -= DataLength;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ DataLength ));
+
+ //
+ // Determine if the entire packet was consumed
+ //
+ if (( 0 == pPacket->ValidBytes )
+ || ( SOCK_STREAM != pPort->pSocket->Type )) {
+ //
+ // All done with this packet
+ // Account for any discarded data
+ //
+ *pSkipBytes = pPacket->ValidBytes;
+ }
+ else
+ {
+ //
+ // More data to consume later
+ //
+ *pbConsumePacket = FALSE;
+ }
+ }
+
+ //
+ // Return the data length and the buffer address
+ //
+ *pDataLength = DataLength;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
+}
+
+
+/**
+ Get the remote socket address.
+
+ This routine returns the address of the remote connection point
+ associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
+
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the TCPv6 address and por number associated with the network adapter.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+**/
+VOID
+EslTcp6RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in6 * pRemoteAddress;
+ ESL_TCP6_CONTEXT * pTcp6;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote address
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ pRemoteAddress = (struct sockaddr_in6 *)pAddress;
+ pRemoteAddress->sin6_family = AF_INET6;
+ pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
+ CopyMem ( &pRemoteAddress->sin6_addr,
+ &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin6_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the remote address
+
+ This routine sets the remote address in the port.
+
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pSockAddr Network address of the remote system.
+
+ @param [in] SockAddrLength Length in bytes of the network address.
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslTcp6RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ CONST struct sockaddr_in6 * pRemoteAddress;
+ ESL_TCP6_CONTEXT * pTcp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Set the remote address
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ pRemoteAddress = (struct sockaddr_in6 *)pSockAddr;
+ CopyMem ( &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr [ 0 ],
+ &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
+ sizeof ( pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 ));
+ pTcp6->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port );
+ Status = EFI_SUCCESS;
+
+//
+// TODO: Fix the following check
+//
+/*
+ if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid remote address\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EAFNOSUPPORT;
+ }
+*/
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the receive completion
+
+ This routine queues the data in FIFO order in either the urgent
+ or normal data queues depending upon the type of data received.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by the TCPv6 driver when some data is
+ received.
+
+ Buffer the data that was just received.
+
+ @param [in] Event The receive completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslTcp6RxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ BOOLEAN bUrgent;
+ size_t LengthInBytes;
+ ESL_PACKET * pPacket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Get the operation status.
+ //
+ Status = pIo->Token.Tcp6Rx.CompletionToken.Status;
+
+ //
+ // +--------------------+ +---------------------------+
+ // | ESL_IO_MGMT | | ESL_PACKET |
+ // | | | |
+ // | +---------------+ +-----------------------+ |
+ // | | Token | | EFI_Tcp6_RECEIVE_DATA | |
+ // | | RxData --> | | |
+ // | | | +-----------------------+---+
+ // | | Event | | Data Buffer |
+ // +----+---------------+ | |
+ // | |
+ // +---------------------------+
+ //
+ //
+ // Duplicate the buffer address and length for use by the
+ // buffer handling code in EslTcp6Receive. These fields are
+ // used when a partial read is done of the data from the
+ // packet.
+ //
+ pPacket = pIo->pPacket;
+ pPacket->pBuffer = pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer;
+ LengthInBytes = pPacket->Op.Tcp6Rx.RxData.DataLength;
+ pPacket->ValidBytes = LengthInBytes;
+
+ //
+ // Get the data type so that it may be linked to the
+ // correct receive buffer list on the ESL_SOCKET structure
+ //
+ bUrgent = pPacket->Op.Tcp6Rx.RxData.UrgentFlag;
+
+ //
+ // Complete this request
+ //
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Start a receive operation
+
+ This routine posts a receive buffer to the TCPv6 driver.
+ See the \ref ReceiveEngine section.
+
+ This support routine is called by EslSocketRxStart.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure.
+
+ **/
+VOID
+EslTcp6RxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ ESL_PACKET * pPacket;
+
+ DBG_ENTER ( );
+
+ //
+ // Initialize the buffer for receive
+ //
+ pPacket = pIo->pPacket;
+ pIo->Token.Tcp6Rx.Packet.RxData = &pPacket->Op.Tcp6Rx.RxData;
+ pPacket->Op.Tcp6Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp6Rx.Buffer );
+ pPacket->Op.Tcp6Rx.RxData.FragmentCount = 1;
+ pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp6Rx.RxData.DataLength;
+ pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Rx.Buffer[0];
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Determine if the socket is configured.
+
+ This routine uses the flag ESL_SOCKET::bConfigured to determine
+ if the network layer's configuration routine has been called.
+
+ This routine is called by EslSocketIsConfigured to verify
+ that the socket has been configured.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
+
+ **/
+ EFI_STATUS
+ EslTcp6SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine the socket configuration status
+ //
+ Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
+
+ //
+ // Return the port connected state.
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Buffer data for transmission over a network connection.
+
+ This routine buffers data for the transmit engine in one of two
+ queues, one for urgent (out-of-band) data and the other for normal
+ data. The urgent data is provided to TCP as soon as it is available,
+ allowing the TCP layer to schedule transmission of the urgent data
+ between packets of normal data.
+
+ This routine is called by ::EslSocketTransmit to buffer
+ data for transmission. When the \ref TransmitEngine has resources,
+ this routine will start the transmission of the next buffer on
+ the network connection.
+
+ Transmission errors are returned during the next transmission or
+ during the close operation. Only buffering errors are returned
+ during the current transmission attempt.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @param [in] Flags Message control flags
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
+ @retval EFI_SUCCESS - Socket data successfully buffered
+
+ **/
+EFI_STATUS
+EslTcp6TxBuffer (
+ IN ESL_SOCKET * pSocket,
+ IN int Flags,
+ IN size_t BufferLength,
+ IN CONST UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
+ )
+{
+ BOOLEAN bUrgent;
+ BOOLEAN bUrgentQueue;
+ ESL_PACKET * pPacket;
+ ESL_IO_MGMT ** ppActive;
+ ESL_IO_MGMT ** ppFree;
+ ESL_PORT * pPort;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ ESL_PACKET * pPreviousPacket;
+ ESL_TCP6_CONTEXT * pTcp6;
+ size_t * pTxBytes;
+ EFI_TCP6_TRANSMIT_DATA * pTxData;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+ *pDataLength = 0;
+
+ //
+ // Verify that the socket is connected
+ //
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine the queue head
+ //
+ pTcp6 = &pPort->Context.Tcp6;
+ bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
+ bUrgentQueue = bUrgent
+ && ( !pSocket->bOobInLine )
+ && pSocket->pApi->bOobSupported;
+ if ( bUrgentQueue ) {
+ ppQueueHead = &pSocket->pTxOobPacketListHead;
+ ppQueueTail = &pSocket->pTxOobPacketListTail;
+ ppActive = &pPort->pTxOobActive;
+ ppFree = &pPort->pTxOobFree;
+ pTxBytes = &pSocket->TxOobBytes;
+ }
+ else {
+ ppQueueHead = &pSocket->pTxPacketListHead;
+ ppQueueTail = &pSocket->pTxPacketListTail;
+ ppActive = &pPort->pTxActive;
+ ppFree = &pPort->pTxFree;
+ pTxBytes = &pSocket->TxBytes;
+ }
+
+ //
+ // Verify that there is enough room to buffer another
+ // transmit operation
+ //
+ if ( pSocket->MaxTxBuf > *pTxBytes ) {
+ if ( pPort->bTxFlowControl ) {
+ DEBUG (( DEBUG_TX,
+ "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
+ pPort,
+ pSocket->MaxTxBuf,
+ *pTxBytes ));
+ pPort->bTxFlowControl = FALSE;
+ }
+
+ //
+ // Attempt to allocate the packet
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ sizeof ( pPacket->Op.Tcp6Tx )
+ - sizeof ( pPacket->Op.Tcp6Tx.Buffer )
+ + BufferLength,
+ 0,
+ DEBUG_TX );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Initialize the transmit operation
+ //
+ pTxData = &pPacket->Op.Tcp6Tx.TxData;
+ pTxData->Push = TRUE || bUrgent;
+ pTxData->Urgent = bUrgent;
+ pTxData->DataLength = (UINT32) BufferLength;
+ pTxData->FragmentCount = 1;
+ pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
+ pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Tx.Buffer[0];
+
+ //
+ // Copy the data into the buffer
+ //
+ CopyMem ( &pPacket->Op.Tcp6Tx.Buffer[0],
+ pBuffer,
+ BufferLength );
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Stop transmission after an error
+ //
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ //
+ // Display the request
+ //
+ DEBUG (( DEBUG_TX,
+ "Send %d %s bytes from 0x%08x\r\n",
+ BufferLength,
+ bUrgent ? L"urgent" : L"normal",
+ pBuffer ));
+
+ //
+ // Queue the data for transmission
+ //
+ pPacket->pNext = NULL;
+ pPreviousPacket = *ppQueueTail;
+ if ( NULL == pPreviousPacket ) {
+ *ppQueueHead = pPacket;
+ }
+ else {
+ pPreviousPacket->pNext = pPacket;
+ }
+ *ppQueueTail = pPacket;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: Packet on %s transmit list\r\n",
+ pPacket,
+ bUrgentQueue ? L"urgent" : L"normal" ));
+
+ //
+ // Account for the buffered data
+ //
+ *pTxBytes += BufferLength;
+ *pDataLength = BufferLength;
+
+ //
+ // Start the transmit engine if it is idle
+ //
+ if ( NULL != *ppFree ) {
+ EslSocketTxStart ( pPort,
+ ppQueueHead,
+ ppQueueTail,
+ ppActive,
+ ppFree );
+ }
+ }
+ else {
+ //
+ // Previous transmit error
+ // Stop transmission
+ //
+ Status = pSocket->TxError;
+ pSocket->errno = EIO;
+
+ //
+ // Free the packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ //
+ // Packet allocation failed
+ //
+ pSocket->errno = ENOMEM;
+ }
+ }
+ else {
+ if ( !pPort->bTxFlowControl ) {
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
+ pPort,
+ pSocket->MaxTxBuf,
+ *pTxBytes ));
+ pPort->bTxFlowControl = TRUE;
+ }
+ //
+ // Not enough buffer space available
+ //
+ pSocket->errno = EAGAIN;
+ Status = EFI_NOT_READY;
+ }
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the normal data transmit completion
+
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for normal data.
+
+ This routine is called by the TCPv6 network layer when a
+ normal data transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo The ESL_IO_MGMT structure address
+
+**/
+VOID
+EslTcp6TxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ UINT32 LengthInBytes;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // Get the transmit length and status
+ //
+ LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;
+ pSocket->TxBytes -= LengthInBytes;
+ Status = pIo->Token.Tcp6Tx.CompletionToken.Status;
+
+ //
+ // Complete the transmit operation
+ //
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Normal ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Process the urgent data transmit completion
+
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for urgent data.
+
+ This routine is called by the TCPv6 network layer when a
+ urgent data transmit request completes.
+
+ @param [in] Event The urgent transmit completion event
+
+ @param [in] pIo The ESL_IO_MGMT structure address
+
+**/
+VOID
+EslTcp6TxOobComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ UINT32 LengthInBytes;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // Get the transmit length and status
+ //
+ LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;
+ pSocket->TxOobBytes -= LengthInBytes;
+ Status = pIo->Token.Tcp6Tx.CompletionToken.Status;
+
+ //
+ // Complete the transmit operation
+ //
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Urgent ",
+ &pSocket->pTxOobPacketListHead,
+ &pSocket->pTxOobPacketListTail,
+ &pPort->pTxOobActive,
+ &pPort->pTxOobFree );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Interface between the socket layer and the network specific
+ code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
+ over TCPv6.
+**/
+CONST ESL_PROTOCOL_API cEslTcp6Api = {
+ "TCPv6",
+ IPPROTO_TCP,
+ OFFSET_OF ( ESL_PORT, Context.Tcp6.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pTcp6List ),
+ sizeof ( struct sockaddr_in6 ),
+ sizeof ( struct sockaddr_in6 ),
+ AF_INET6,
+ sizeof (((ESL_PACKET *)0 )->Op.Tcp6Rx ),
+ OFFSET_OF ( ESL_PACKET, Op.Tcp6Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Rx.Packet.RxData ),
+ TRUE,
+ EADDRINUSE,
+ EslTcp6Accept,
+ EslTcp6ConnectPoll,
+ EslTcp6ConnectStart,
+ EslTcp6SocketIsConfigured,
+ EslTcp6LocalAddressGet,
+ EslTcp6LocalAddressSet,
+ EslTcp6Listen,
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslTcp6PacketFree,
+ EslTcp6PortAllocate,
+ EslTcp6PortClose,
+ EslTcp6PortCloseOp,
+ FALSE,
+ EslTcp6Receive,
+ EslTcp6RemoteAddressGet,
+ EslTcp6RemoteAddressSet,
+ EslTcp6RxComplete,
+ EslTcp6RxStart,
+ EslTcp6TxBuffer,
+ EslTcp6TxComplete,
+ EslTcp6TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/Udp4.c b/StdLib/EfiSocketLib/Udp4.c
index e1500d3f9f..6625c078d0 100644
--- a/StdLib/EfiSocketLib/Udp4.c
+++ b/StdLib/EfiSocketLib/Udp4.c
@@ -253,6 +253,7 @@ EslUdp4PortAllocate (
//
pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;
pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;
+ pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv4->Poll;
pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
diff --git a/StdLib/EfiSocketLib/Udp6.c b/StdLib/EfiSocketLib/Udp6.c
new file mode 100644
index 0000000000..187f0ad641
--- /dev/null
+++ b/StdLib/EfiSocketLib/Udp6.c
@@ -0,0 +1,1094 @@
+/** @file
+ Implement the UDP4 driver support for the socket layer.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ 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 "Socket.h"
+
+
+/**
+ Get the local socket address
+
+ This routine returns the IPv6 address and UDP port number associated
+ with the local socket.
+
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_DGRAM socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pSockAddr Network address to receive the local system address
+
+**/
+VOID
+EslUdp6LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
+ )
+{
+ struct sockaddr_in6 * pLocalAddress;
+ ESL_UDP6_CONTEXT * pUdp6;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pUdp6 = &pPort->Context.Udp6;
+ pLocalAddress = (struct sockaddr_in6 *)pSockAddr;
+ pLocalAddress->sin6_family = AF_INET6;
+ pLocalAddress->sin6_port = SwapBytes16 ( pUdp6->ConfigData.StationPort );
+ CopyMem ( &pLocalAddress->sin6_addr,
+ &pUdp6->ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin6_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the local port address.
+
+ This routine sets the local port address.
+
+ This support routine is called by ::EslSocketPortAllocate.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv6 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv6 address restricts the connection to the
+ network stack supporting that address. Specifying zero
+ for the port causes the network layer to assign a port
+ number from the dynamic range. Specifying a specific
+ port number causes the network layer to use that port.
+
+ @param [in] bBindTest TRUE = run bind testing
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslUdp6LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
+ )
+{
+ EFI_UDP6_CONFIG_DATA * pConfig;
+ CONST struct sockaddr_in6 * pIpAddress;
+ CONST UINT8 * pIPv6Address;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Set the local address
+ //
+ pIpAddress = (struct sockaddr_in6 *)pSockAddr;
+ pIPv6Address = (UINT8 *)&pIpAddress->sin6_addr;
+ pConfig = &pPort->Context.Udp6.ConfigData;
+ CopyMem ( &pConfig->StationAddress,
+ pIPv6Address,
+ sizeof ( pConfig->StationAddress ));
+
+ //
+ // Validate the IP address
+ //
+ pConfig->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Set the port number
+ //
+ pConfig->StationPort = SwapBytes16 ( pIpAddress->sin6_port );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local UDP6 Address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pConfig->StationAddress.Addr[0],
+ pConfig->StationAddress.Addr[1],
+ pConfig->StationAddress.Addr[2],
+ pConfig->StationAddress.Addr[3],
+ pConfig->StationAddress.Addr[4],
+ pConfig->StationAddress.Addr[5],
+ pConfig->StationAddress.Addr[6],
+ pConfig->StationAddress.Addr[7],
+ pConfig->StationAddress.Addr[8],
+ pConfig->StationAddress.Addr[9],
+ pConfig->StationAddress.Addr[10],
+ pConfig->StationAddress.Addr[11],
+ pConfig->StationAddress.Addr[12],
+ pConfig->StationAddress.Addr[13],
+ pConfig->StationAddress.Addr[14],
+ pConfig->StationAddress.Addr[15],
+ pConfig->StationPort ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
+
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
+
+**/
+VOID
+EslUdp6PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ EFI_UDP6_RECEIVE_DATA * pRxData;
+
+ DBG_ENTER ( );
+
+ //
+ // Account for the receive bytes
+ //
+ pRxData = pPacket->Op.Udp6Rx.pRxData;
+ *pRxBytes -= pRxData->DataLength;
+
+ //
+ // Disconnect the buffer from the packet
+ //
+ pPacket->Op.Udp6Rx.pRxData = NULL;
+
+ //
+ // Return the buffer to the UDP6 driver
+ //
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Initialize the network specific portions of an ::ESL_PORT structure.
+
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
+
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the UDPv4 protocol.
+
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslUdp6PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_UDP6_CONFIG_DATA * pConfig;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Initialize the port
+ //
+ pSocket = pPort->pSocket;
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp6Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp6Tx.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP6_COMPLETION_TOKEN, Packet.TxData );
+
+ //
+ // Save the cancel, receive and transmit addresses
+ //
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv6->Configure;
+ pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Cancel;
+ pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv6->Poll;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv6->Transmit;
+
+ //
+ // Do not drop packets
+ //
+ pConfig = &pPort->Context.Udp6.ConfigData;
+ pConfig->ReceiveTimeout = 0;
+ pConfig->ReceiveTimeout = pConfig->ReceiveTimeout;
+
+ //
+ // Set the configuration flags
+ //
+ pConfig->AllowDuplicatePort = TRUE;
+ pConfig->AcceptAnyPort = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->HopLimit = 255;
+ pConfig->TrafficClass = 0;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Receive data from a network connection.
+
+ This routine attempts to return buffered data to the caller. The
+ data is removed from the urgent queue if the message flag MSG_OOB
+ is specified, otherwise data is removed from the normal queue.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_DGRAM sockets.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
+
+ @return Returns the address of the next free byte in the buffer.
+
+ **/
+UINT8 *
+EslUdp6Receive (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET * pPacket,
+ IN BOOLEAN * pbConsumePacket,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ OUT size_t * pSkipBytes
+ )
+{
+ size_t DataBytes;
+ struct sockaddr_in6 * pRemoteAddress;
+ EFI_UDP6_RECEIVE_DATA * pRxData;
+
+ DBG_ENTER ( );
+
+ pRxData = pPacket->Op.Udp6Rx.pRxData;
+ //
+ // Return the remote system address if requested
+ //
+ if ( NULL != pAddress ) {
+ //
+ // Build the remote address
+ //
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pRxData->UdpSession.SourceAddress.Addr[0],
+ pRxData->UdpSession.SourceAddress.Addr[1],
+ pRxData->UdpSession.SourceAddress.Addr[2],
+ pRxData->UdpSession.SourceAddress.Addr[3],
+ pRxData->UdpSession.SourceAddress.Addr[4],
+ pRxData->UdpSession.SourceAddress.Addr[5],
+ pRxData->UdpSession.SourceAddress.Addr[6],
+ pRxData->UdpSession.SourceAddress.Addr[7],
+ pRxData->UdpSession.SourceAddress.Addr[8],
+ pRxData->UdpSession.SourceAddress.Addr[9],
+ pRxData->UdpSession.SourceAddress.Addr[10],
+ pRxData->UdpSession.SourceAddress.Addr[11],
+ pRxData->UdpSession.SourceAddress.Addr[12],
+ pRxData->UdpSession.SourceAddress.Addr[13],
+ pRxData->UdpSession.SourceAddress.Addr[14],
+ pRxData->UdpSession.SourceAddress.Addr[15],
+ pRxData->UdpSession.SourcePort ));
+ pRemoteAddress = (struct sockaddr_in6 *)pAddress;
+ CopyMem ( &pRemoteAddress->sin6_addr,
+ &pRxData->UdpSession.SourceAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin6_addr ));
+ pRemoteAddress->sin6_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
+ }
+
+ //
+ // Copy the received data
+ //
+ pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
+ (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
+ BufferLength,
+ pBuffer,
+ &DataBytes );
+
+ //
+ // Determine if the data is being read
+ //
+ if ( *pbConsumePacket ) {
+ //
+ // Display for the bytes consumed
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ DataBytes ));
+
+ //
+ // Account for any discarded data
+ //
+ *pSkipBytes = pRxData->DataLength - DataBytes;
+ }
+
+ //
+ // Return the data length and the buffer address
+ //
+ *pDataLength = DataBytes;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
+}
+
+
+/**
+ Get the remote socket address
+
+ This routine returns the address of the remote connection point
+ associated with the SOCK_DGRAM socket.
+
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the UDPv4 address and port number associated with the network adapter.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+**/
+VOID
+EslUdp6RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in6 * pRemoteAddress;
+ ESL_UDP6_CONTEXT * pUdp6;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote address
+ //
+ pUdp6 = &pPort->Context.Udp6;
+ pRemoteAddress = (struct sockaddr_in6 *)pAddress;
+ pRemoteAddress->sin6_family = AF_INET6;
+ pRemoteAddress->sin6_port = SwapBytes16 ( pUdp6->ConfigData.RemotePort );
+ CopyMem ( &pRemoteAddress->sin6_addr,
+ &pUdp6->ConfigData.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin6_addr ));
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Set the remote address
+
+ This routine sets the remote address in the port.
+
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [in] pSockAddr Network address of the remote system.
+
+ @param [in] SockAddrLength Length in bytes of the network address.
+
+ @retval EFI_SUCCESS The operation was successful
+
+ **/
+EFI_STATUS
+EslUdp6RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ CONST struct sockaddr_in6 * pRemoteAddress;
+ ESL_UDP6_CONTEXT * pUdp6;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Set the remote address
+ //
+ pUdp6 = &pPort->Context.Udp6;
+ pRemoteAddress = (struct sockaddr_in6 *)pSockAddr;
+ CopyMem ( &pUdp6->ConfigData.RemoteAddress,
+ &pRemoteAddress->sin6_addr,
+ sizeof ( pUdp6->ConfigData.RemoteAddress ));
+ pUdp6->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port );
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the receive completion
+
+ This routine keeps the UDPv4 driver's buffer and queues it in
+ in FIFO order to the data queue. The UDP6 driver's buffer will
+ be returned by either ::EslUdp6Receive or ::EslSocketPortCloseTxDone.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by the UDPv4 driver when data is
+ received.
+
+ @param [in] Event The receive completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslUdp6RxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ size_t LengthInBytes;
+ ESL_PACKET * pPacket;
+ EFI_UDP6_RECEIVE_DATA * pRxData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Get the operation status.
+ //
+ Status = pIo->Token.Udp6Rx.Status;
+
+ //
+ // Get the packet length
+ //
+ pRxData = pIo->Token.Udp6Rx.Packet.RxData;
+ LengthInBytes = pRxData->DataLength;
+
+ //
+ // +--------------------+ +-----------------------+
+ // | ESL_IO_MGMT | | Data Buffer |
+ // | | | (Driver owned) |
+ // | +---------------+ +-----------------------+
+ // | | Token | ^
+ // | | Rx Event | |
+ // | | | +-----------------------+
+ // | | RxData --> | EFI_UDP6_RECEIVE_DATA |
+ // +----+---------------+ | (Driver owned) |
+ // +-----------------------+
+ // +--------------------+ ^
+ // | ESL_PACKET | .
+ // | | .
+ // | +---------------+ .
+ // | | pRxData --> NULL .......
+ // +----+---------------+
+ //
+ //
+ // Save the data in the packet
+ //
+ pPacket = pIo->pPacket;
+ pPacket->Op.Udp6Rx.pRxData = pRxData;
+
+ //
+ // Complete this request
+ //
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Determine if the socket is configured.
+
+ This routine uses the flag ESL_SOCKET::bConfigured to determine
+ if the network layer's configuration routine has been called.
+ This routine calls the bind and configuration routines if they
+ were not already called. After the port is configured, the
+ \ref ReceiveEngine is started.
+
+ This routine is called by EslSocketIsConfigured to verify
+ that the socket is configured.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
+
+ **/
+ EFI_STATUS
+ EslUdp6SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ EFI_UDP6_CONFIG_DATA * pConfigData;
+ ESL_PORT * pPort;
+ ESL_PORT * pNextPort;
+ ESL_UDP6_CONTEXT * pUdp6;
+ EFI_UDP6_PROTOCOL * pUdp6Protocol;
+ EFI_STATUS Status;
+ struct sockaddr_in6 LocalAddress;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Configure the port if necessary
+ //
+ if ( !pSocket->bConfigured ) {
+ //
+ // Fill in the port list if necessary
+ //
+ if ( NULL == pSocket->pPortList ) {
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
+ LocalAddress.sin6_len = sizeof ( LocalAddress );
+ LocalAddress.sin6_family = AF_INET6;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin6_len,
+ &pSocket->errno );
+ }
+
+ //
+ // Walk the port list
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Attempt to configure the port
+ //
+ pNextPort = pPort->pLinkSocket;
+ pUdp6 = &pPort->Context.Udp6;
+ pUdp6Protocol = pPort->pProtocol.UDPv6;
+ pConfigData = &pUdp6->ConfigData;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configuring for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d --> [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationAddress.Addr[4],
+ pConfigData->StationAddress.Addr[5],
+ pConfigData->StationAddress.Addr[6],
+ pConfigData->StationAddress.Addr[7],
+ pConfigData->StationAddress.Addr[8],
+ pConfigData->StationAddress.Addr[9],
+ pConfigData->StationAddress.Addr[10],
+ pConfigData->StationAddress.Addr[11],
+ pConfigData->StationAddress.Addr[12],
+ pConfigData->StationAddress.Addr[13],
+ pConfigData->StationAddress.Addr[14],
+ pConfigData->StationAddress.Addr[15],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemoteAddress.Addr[4],
+ pConfigData->RemoteAddress.Addr[5],
+ pConfigData->RemoteAddress.Addr[6],
+ pConfigData->RemoteAddress.Addr[7],
+ pConfigData->RemoteAddress.Addr[8],
+ pConfigData->RemoteAddress.Addr[9],
+ pConfigData->RemoteAddress.Addr[10],
+ pConfigData->RemoteAddress.Addr[11],
+ pConfigData->RemoteAddress.Addr[12],
+ pConfigData->RemoteAddress.Addr[13],
+ pConfigData->RemoteAddress.Addr[14],
+ pConfigData->RemoteAddress.Addr[15],
+ pConfigData->RemotePort ));
+ Status = pUdp6Protocol->Configure ( pUdp6Protocol,
+ pConfigData );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Update the configuration data
+ //
+ Status = pUdp6Protocol->GetModeData ( pUdp6Protocol,
+ pConfigData,
+ NULL,
+ NULL,
+ NULL );
+ }
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_LISTEN,
+ "ERROR - Failed to configure the Udp6 port, Status: %r\r\n",
+ Status ));
+ switch ( Status ) {
+ case EFI_ACCESS_DENIED:
+ pSocket->errno = EACCES;
+ break;
+
+ default:
+ case EFI_DEVICE_ERROR:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ pSocket->errno = EADDRNOTAVAIL;
+ break;
+
+ case EFI_NO_MAPPING:
+ pSocket->errno = EAFNOSUPPORT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
+
+ case EFI_UNSUPPORTED:
+ pSocket->errno = EOPNOTSUPP;
+ break;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configured for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d --> [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationAddress.Addr[4],
+ pConfigData->StationAddress.Addr[5],
+ pConfigData->StationAddress.Addr[6],
+ pConfigData->StationAddress.Addr[7],
+ pConfigData->StationAddress.Addr[8],
+ pConfigData->StationAddress.Addr[9],
+ pConfigData->StationAddress.Addr[10],
+ pConfigData->StationAddress.Addr[11],
+ pConfigData->StationAddress.Addr[12],
+ pConfigData->StationAddress.Addr[13],
+ pConfigData->StationAddress.Addr[14],
+ pConfigData->StationAddress.Addr[15],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemoteAddress.Addr[4],
+ pConfigData->RemoteAddress.Addr[5],
+ pConfigData->RemoteAddress.Addr[6],
+ pConfigData->RemoteAddress.Addr[7],
+ pConfigData->RemoteAddress.Addr[8],
+ pConfigData->RemoteAddress.Addr[9],
+ pConfigData->RemoteAddress.Addr[10],
+ pConfigData->RemoteAddress.Addr[11],
+ pConfigData->RemoteAddress.Addr[12],
+ pConfigData->RemoteAddress.Addr[13],
+ pConfigData->RemoteAddress.Addr[14],
+ pConfigData->RemoteAddress.Addr[15],
+ pConfigData->RemotePort ));
+ pPort->bConfigured = TRUE;
+
+ //
+ // Start the first read on the port
+ //
+ EslSocketRxStart ( pPort );
+
+ //
+ // The socket is connected
+ //
+ pSocket->State = SOCKET_STATE_CONNECTED;
+ }
+
+ //
+ // Set the next port
+ //
+ pPort = pNextPort;
+ }
+
+ //
+ // Determine the configuration status
+ //
+ if ( NULL != pSocket->pPortList ) {
+ pSocket->bConfigured = TRUE;
+ }
+ }
+
+ //
+ // Determine the socket configuration status
+ //
+ if ( !EFI_ERROR ( Status )) {
+ Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
+ }
+
+ //
+ // Return the port connected state.
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Buffer data for transmission over a network connection.
+
+ This routine buffers data for the transmit engine in the normal
+ data queue. When the \ref TransmitEngine has resources, this
+ routine will start the transmission of the next buffer on the
+ network connection.
+
+ This routine is called by ::EslSocketTransmit to buffer
+ data for transmission. The data is copied into a local buffer
+ freeing the application buffer for reuse upon return. When
+ necessary, this routine starts the transmit engine that
+ performs the data transmission on the network connection. The
+ transmit engine transmits the data a packet at a time over the
+ network connection.
+
+ Transmission errors are returned during the next transmission or
+ during the close operation. Only buffering errors are returned
+ during the current transmission attempt.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @param [in] Flags Message control flags
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
+ @retval EFI_SUCCESS - Socket data successfully buffered
+
+**/
+EFI_STATUS
+EslUdp6TxBuffer (
+ IN ESL_SOCKET * pSocket,
+ IN int Flags,
+ IN size_t BufferLength,
+ IN CONST UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
+ )
+{
+ ESL_PACKET * pPacket;
+ ESL_PACKET * pPreviousPacket;
+ ESL_PORT * pPort;
+ const struct sockaddr_in6 * pRemoteAddress;
+ ESL_UDP6_CONTEXT * pUdp6;
+ size_t * pTxBytes;
+ ESL_UDP6_TX_DATA * pTxData;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+ *pDataLength = 0;
+
+ //
+ // Verify that the socket is connected
+ //
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine the queue head
+ //
+ pUdp6 = &pPort->Context.Udp6;
+ pTxBytes = &pSocket->TxBytes;
+
+ //
+ // Verify that there is enough room to buffer another
+ // transmit operation
+ //
+ if ( pSocket->MaxTxBuf > *pTxBytes ) {
+ //
+ // Attempt to allocate the packet
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ sizeof ( pPacket->Op.Udp6Tx )
+ - sizeof ( pPacket->Op.Udp6Tx.Buffer )
+ + BufferLength,
+ 0,
+ DEBUG_TX );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Initialize the transmit operation
+ //
+ pTxData = &pPacket->Op.Udp6Tx;
+ pTxData->TxData.UdpSessionData = NULL;
+ pTxData->TxData.DataLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentCount = 1;
+ pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp6Tx.Buffer[0];
+
+ //
+ // Set the remote system address if necessary
+ //
+ pTxData->TxData.UdpSessionData = NULL;
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (const struct sockaddr_in6 *)pAddress;
+ CopyMem ( &pTxData->Session.SourceAddress,
+ &pUdp6->ConfigData.StationAddress,
+ sizeof ( pTxData->Session.SourceAddress ));
+ pTxData->Session.SourcePort = 0;
+ CopyMem ( &pTxData->Session.DestinationAddress,
+ &pRemoteAddress->sin6_addr,
+ sizeof ( pTxData->Session.DestinationAddress ));
+ pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin6_port );
+
+ //
+ // Use the remote system address when sending this packet
+ //
+ pTxData->TxData.UdpSessionData = &pTxData->Session;
+ }
+
+ //
+ // Copy the data into the buffer
+ //
+ CopyMem ( &pPacket->Op.Udp6Tx.Buffer[0],
+ pBuffer,
+ BufferLength );
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Stop transmission after an error
+ //
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ //
+ // Display the request
+ //
+ DEBUG (( DEBUG_TX,
+ "Send %d %s bytes from 0x%08x\r\n",
+ BufferLength,
+ pBuffer ));
+
+ //
+ // Queue the data for transmission
+ //
+ pPacket->pNext = NULL;
+ pPreviousPacket = pSocket->pTxPacketListTail;
+ if ( NULL == pPreviousPacket ) {
+ pSocket->pTxPacketListHead = pPacket;
+ }
+ else {
+ pPreviousPacket->pNext = pPacket;
+ }
+ pSocket->pTxPacketListTail = pPacket;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: Packet on transmit list\r\n",
+ pPacket ));
+
+ //
+ // Account for the buffered data
+ //
+ *pTxBytes += BufferLength;
+ *pDataLength = BufferLength;
+
+ //
+ // Start the transmit engine if it is idle
+ //
+ if ( NULL != pPort->pTxFree ) {
+ EslSocketTxStart ( pPort,
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ }
+ }
+ else {
+ //
+ // Previous transmit error
+ // Stop transmission
+ //
+ Status = pSocket->TxError;
+ pSocket->errno = EIO;
+
+ //
+ // Free the packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ //
+ // Packet allocation failed
+ //
+ pSocket->errno = ENOMEM;
+ }
+ }
+ else {
+ //
+ // Not enough buffer space available
+ //
+ pSocket->errno = EAGAIN;
+ Status = EFI_NOT_READY;
+ }
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the transmit completion
+
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for data packets.
+
+ This routine is called by the UDPv4 network layer when a data
+ transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslUdp6TxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ UINT32 LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // Get the transmit length and status
+ //
+ LengthInBytes = pPacket->Op.Udp6Tx.TxData.DataLength;
+ pSocket->TxBytes -= LengthInBytes;
+ Status = pIo->Token.Udp6Tx.Status;
+
+ //
+ // Complete the transmit operation
+ //
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "UDP ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Interface between the socket layer and the network specific
+ code that supports SOCK_DGRAM sockets over UDPv4.
+**/
+CONST ESL_PROTOCOL_API cEslUdp6Api = {
+ "UDPv6",
+ IPPROTO_UDP,
+ OFFSET_OF ( ESL_PORT, Context.Udp6.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pUdp6List ),
+ sizeof ( struct sockaddr_in6 ),
+ sizeof ( struct sockaddr_in6 ),
+ AF_INET6,
+ sizeof (((ESL_PACKET *)0 )->Op.Udp6Rx ),
+ sizeof (((ESL_PACKET *)0 )->Op.Udp6Rx ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Udp6Rx.Packet.RxData ),
+ FALSE,
+ EADDRINUSE,
+ NULL, // Accept
+ NULL, // ConnectPoll
+ NULL, // ConnectStart
+ EslUdp6SocketIsConfigured,
+ EslUdp6LocalAddressGet,
+ EslUdp6LocalAddressSet,
+ NULL, // Listen
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslUdp6PacketFree,
+ EslUdp6PortAllocate,
+ NULL, // PortClose,
+ NULL, // PortCloseOp
+ TRUE,
+ EslUdp6Receive,
+ EslUdp6RemoteAddressGet,
+ EslUdp6RemoteAddressSet,
+ EslUdp6RxComplete,
+ NULL, // RxStart
+ EslUdp6TxBuffer,
+ EslUdp6TxComplete,
+ NULL // TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/UseEfiSocketLib.c b/StdLib/EfiSocketLib/UseEfiSocketLib.c
index 1c122af650..ed72e8e763 100644
--- a/StdLib/EfiSocketLib/UseEfiSocketLib.c
+++ b/StdLib/EfiSocketLib/UseEfiSocketLib.c
@@ -29,6 +29,14 @@ CONST EFI_GUID mEslIp4ServiceGuid = {
/**
+ Tag GUID - IPv6 in use by an application using EfiSocketLib
+**/
+CONST EFI_GUID mEslIp6ServiceGuid = {
+ 0xc51b2761, 0xc476, 0x45fe, { 0xbe, 0x61, 0xba, 0x4b, 0xcc, 0x32, 0xf2, 0x34 }
+};
+
+
+/**
Tag GUID - TCPv4 in use by an application using EfiSocketLib
**/
CONST EFI_GUID mEslTcp4ServiceGuid = {
@@ -37,6 +45,14 @@ CONST EFI_GUID mEslTcp4ServiceGuid = {
/**
+ Tag GUID - TCPv6 in use by an application using EfiSocketLib
+**/
+CONST EFI_GUID mEslTcp6ServiceGuid = {
+ 0x279858a4, 0x4e9e, 0x4e53, { 0x93, 0x22, 0xf2, 0x54, 0xe0, 0x7e, 0xef, 0xd4 }
+};
+
+
+/**
Tag GUID - UDPv4 in use by an application using EfiSocketLib
**/
CONST EFI_GUID mEslUdp4ServiceGuid = {
@@ -45,6 +61,14 @@ CONST EFI_GUID mEslUdp4ServiceGuid = {
/**
+ Tag GUID - UDPv6 in use by an application using EfiSocketLib
+**/
+CONST EFI_GUID mEslUdp6ServiceGuid = {
+ 0xaa4af677, 0x6efe, 0x477c, { 0x96, 0x68, 0xe8, 0x13, 0x9d, 0x2, 0xfd, 0x9b }
+};
+
+
+/**
Connect to the EFI socket library
This routine creates the ::ESL_SOCKET structure and returns
@@ -252,10 +276,8 @@ EslServiceNetworkDisconnect (
NULL,
&HandleCount,
&pHandles );
- if ( EFI_ERROR ( Status )) {
- break;
- }
- if ( NULL != pHandles ) {
+ if (( !EFI_ERROR ( Status ))
+ && ( NULL != pHandles )) {
//
// Attempt to disconnect from this network adapter
//
@@ -277,6 +299,7 @@ EslServiceNetworkDisconnect (
// Set the next network protocol
//
pSocketBinding += 1;
+ Status = EFI_SUCCESS;
}
//