summaryrefslogtreecommitdiff
path: root/StdLib
diff options
context:
space:
mode:
authorlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-30 23:02:35 +0000
committerlpleahy <lpleahy@6f19259b-4bc3-4df7-8a09-765794883524>2011-09-30 23:02:35 +0000
commita88c31639bb24c73383a4528a5b77066e805148b (patch)
tree058801cd8687b0a0c6f82459b56b2ad3beb43bf4 /StdLib
parentdf7499fcc1fbd6c825cabf19bbed379688416125 (diff)
downloadedk2-platforms-a88c31639bb24c73383a4528a5b77066e805148b.tar.xz
Update the sockets library code
* Passes conformance and functional tests. * Builds with GCC 4.4 compiler. Signed-off by: lpleahy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12497 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'StdLib')
-rw-r--r--StdLib/BsdSocketLib/SocketInternals.h25
-rw-r--r--StdLib/BsdSocketLib/Socklib_internals.h48
-rw-r--r--StdLib/BsdSocketLib/accept.c50
-rw-r--r--StdLib/BsdSocketLib/bind.c7
-rw-r--r--StdLib/BsdSocketLib/close.c8
-rw-r--r--StdLib/BsdSocketLib/connect.c21
-rw-r--r--StdLib/BsdSocketLib/errno.c3
-rw-r--r--StdLib/BsdSocketLib/getpeername.c7
-rw-r--r--StdLib/BsdSocketLib/getsockname.c7
-rw-r--r--StdLib/BsdSocketLib/getsockopt.c8
-rw-r--r--StdLib/BsdSocketLib/listen.c13
-rw-r--r--StdLib/BsdSocketLib/read.c6
-rw-r--r--StdLib/BsdSocketLib/recv.c12
-rw-r--r--StdLib/BsdSocketLib/recvfrom.c12
-rw-r--r--StdLib/BsdSocketLib/res_send.c2
-rw-r--r--StdLib/BsdSocketLib/send.c9
-rw-r--r--StdLib/BsdSocketLib/sendto.c35
-rw-r--r--StdLib/BsdSocketLib/sethostname.c2
-rw-r--r--StdLib/BsdSocketLib/setsockopt.c8
-rw-r--r--StdLib/BsdSocketLib/shutdown.c7
-rw-r--r--StdLib/BsdSocketLib/socket.c51
-rw-r--r--StdLib/BsdSocketLib/write.c1
-rw-r--r--StdLib/EfiSocketLib/DxeSupport.c322
-rw-r--r--StdLib/EfiSocketLib/EfiSocketLib.inf5
-rw-r--r--StdLib/EfiSocketLib/Init.c34
-rw-r--r--StdLib/EfiSocketLib/Ip4.c1264
-rw-r--r--StdLib/EfiSocketLib/ReleaseNotes.txt31
-rw-r--r--StdLib/EfiSocketLib/Service.c201
-rw-r--r--StdLib/EfiSocketLib/Socket.c5046
-rw-r--r--StdLib/EfiSocketLib/Socket.h1762
-rw-r--r--StdLib/EfiSocketLib/Tcp4.c2973
-rw-r--r--StdLib/EfiSocketLib/Udp4.c2264
-rw-r--r--StdLib/EfiSocketLib/UseEfiSocketLib.c138
-rw-r--r--StdLib/Include/Efi/EfiSocketLib.h456
-rw-r--r--StdLib/Include/Protocol/EfiSocket.h332
-rw-r--r--StdLib/SocketDxe/ComponentName.c6
-rw-r--r--StdLib/SocketDxe/DriverBinding.c71
-rw-r--r--StdLib/SocketDxe/EntryUnload.c63
-rw-r--r--StdLib/SocketDxe/Socket.h6
-rw-r--r--StdLib/UseSocketDxe/UseSocketDxe.c24
40 files changed, 8756 insertions, 6584 deletions
diff --git a/StdLib/BsdSocketLib/SocketInternals.h b/StdLib/BsdSocketLib/SocketInternals.h
index 8fbd8420dc..1b19869c0d 100644
--- a/StdLib/BsdSocketLib/SocketInternals.h
+++ b/StdLib/BsdSocketLib/SocketInternals.h
@@ -57,7 +57,7 @@
address for the file
@param [in] pErrno Address of the errno variable
- @return A pointer to the socket protocol structure or NULL if
+ @return A pointer to the EFI_SOCKET_PROTOCOL structure or NULL if
an invalid file descriptor was passed in.
**/
@@ -71,13 +71,17 @@ BslFdToSocketProtocol (
/**
Close the socket
- @param [in] pDescriptor Descriptor address for the file
+ The BslSocketClose routine is called indirectly from the close file
+ system routine. This routine closes the socket and returns the
+ status to the caller.
+
+ @param[in] pDescriptor Descriptor address for the file
@return This routine returns 0 upon success and -1 upon failure.
- In the case of failure, errno contains more information.
+ In the case of failure, ::errno contains more information.
**/
-INT32
+int
BslSocketClose (
struct __filedes * pDescriptor
);
@@ -85,9 +89,9 @@ BslSocketClose (
/**
Worker routine to close the socket.
- @param [in] pSocketProtocol Socket protocol structure address
+ @param[in] pSocketProtocol Socket protocol structure address
- @param [in] pErrno Address of the errno variable
+ @param[in] pErrno Address of the ::errno variable
@retval EFI_SUCCESS Successfully closed the socket
@@ -133,12 +137,18 @@ BslSocketProtocolToFd (
/**
Read support routine for sockets
+ The BslSocketRead routine is called indirectly by the read file
+ system routine. This routine is typically used for SOCK_STREAM
+ because it waits for receive data from the target system specified
+ in the ::connect call.
+
@param [in] pDescriptor Descriptor address for the file
@param [in] pOffset File offset
@param [in] LengthInBytes Number of bytes to read
@param [in] pBuffer Address of the buffer to receive the data
@return The number of bytes read or -1 if an error occurs.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
@@ -158,6 +168,7 @@ BslSocketRead (
@param [in] pBuffer Address of the data
@return The number of bytes written or -1 if an error occurs.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
@@ -175,7 +186,7 @@ BslSocketWrite (
@param [in] pErrno Address of the errno variable
- @return A pointer to the socket protocol structure or NULL if
+ @return A pointer to the EFI_SOCKET_PROTOCOL structure or NULL if
an invalid file descriptor was passed in.
**/
diff --git a/StdLib/BsdSocketLib/Socklib_internals.h b/StdLib/BsdSocketLib/Socklib_internals.h
index 802aaebcc6..3e0119fd18 100644
--- a/StdLib/BsdSocketLib/Socklib_internals.h
+++ b/StdLib/BsdSocketLib/Socklib_internals.h
@@ -1,4 +1,4 @@
-/** @file
+/*
Definitions for the socket library functions that are used internally.
Copyright (c) 2011, Intel Corporation
@@ -10,33 +10,33 @@
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-**/
+*/
#ifndef _SOCKLIB_INTERNALS_H_
#define _SOCKLIB_INTERNALS_H_
-void _sethosthtent(int);
-void _endhosthtent(void);
-void _sethostdnsent(int);
-void _endhostdnsent(void);
-void _setnethtent(int);
-void _endnethtent(void);
-void _setnetdnsent(int);
-void _endnetdnsent(void);
+void _sethosthtent (int);
+void _endhosthtent (void);
+void _sethostdnsent (int);
+void _endhostdnsent (void);
+void _setnethtent (int);
+void _endnethtent (void);
+void _setnetdnsent (int);
+void _endnetdnsent (void);
-struct hostent * _gethostbyhtname(const char *, int);
-struct hostent * _gethostbydnsname(const char *, int);
-struct hostent * _gethostbynisname(const char *, int);
-struct hostent * _gethostbyhtaddr(const char *, int, int);
-struct hostent * _gethostbydnsaddr(const char *, int, int);
-struct hostent * _gethostbynisaddr(const char *, int, int);
-struct netent * _getnetbyhtname(const char *);
-struct netent * _getnetbydnsname(const char *);
-struct netent * _getnetbynisname(const char *);
-struct netent * _getnetbyhtaddr(unsigned long, int);
-struct netent * _getnetbydnsaddr(unsigned long, int);
-struct netent * _getnetbynisaddr(unsigned long, int);
-void _map_v4v6_address(const char *src, char *dst);
-void _map_v4v6_hostent(struct hostent *hp, char **bp, int *len);
+struct hostent * _gethostbyhtname (const char *, int);
+struct hostent * _gethostbydnsname (const char *, int);
+struct hostent * _gethostbynisname (const char *, int);
+struct hostent * _gethostbyhtaddr (const char *, int, int);
+struct hostent * _gethostbydnsaddr (const char *, int, int);
+struct hostent * _gethostbynisaddr (const char *, int, int);
+struct netent * _getnetbyhtname (const char *);
+struct netent * _getnetbydnsname (const char *);
+struct netent * _getnetbynisname (const char *);
+struct netent * _getnetbyhtaddr (unsigned long, int);
+struct netent * _getnetbydnsaddr (unsigned long, int);
+struct netent * _getnetbynisaddr (unsigned long, int);
+void _map_v4v6_address (const char *src, char *dst);
+void _map_v4v6_hostent (struct hostent *hp, char **bp, int *len);
#endif
diff --git a/StdLib/BsdSocketLib/accept.c b/StdLib/BsdSocketLib/accept.c
index 25ae1b5861..4f0dbac5f9 100644
--- a/StdLib/BsdSocketLib/accept.c
+++ b/StdLib/BsdSocketLib/accept.c
@@ -16,29 +16,30 @@
/**
- Worker routine for ::Accept and ::AcceptNB
+ Worker routine for ::accept and ::AcceptNB
- @param [in] s Socket file descriptor returned from ::socket.
+ @param [in] s Socket file descriptor returned from ::socket.
- @param [in] bBlocking TRUE if this is a blocking call
- @param [in] address Address of a buffer to receive the remote network address.
+ @param [in] bBlockingAllowed TRUE if this is a blocking call
+ @param [in] address Address of a buffer to receive the remote network address.
@param [in, out] address_len Address of a buffer containing the Length in bytes
of the remote network address buffer. Upon return,
contains the length of the remote network address.
- @return ::accept returns zero if successful and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ @return AcceptWork returns zero if successful and -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
AcceptWork (
int s,
- BOOLEAN bBlocking,
+ BOOLEAN bBlockingAllowed,
struct sockaddr * address,
socklen_t * address_len
)
{
+ BOOLEAN bBlocking;
INT32 NewSocketFd;
struct __filedes * pDescriptor;
EFI_SOCKET_PROTOCOL * pNewSocket;
@@ -58,8 +59,10 @@ AcceptWork (
&errno );
if ( NULL != pSocketProtocol ) {
//
- // TODO: Update bBlocking by anding with check for NON_BLOCKING
+ // Determine if the operation is blocking
//
+ bBlocking = (BOOLEAN)( 0 == ( pDescriptor->Oflags & O_NONBLOCK ));
+ bBlocking &= bBlockingAllowed;
//
// Attempt to accept a new network connection
@@ -75,12 +78,14 @@ AcceptWork (
//
// Convert the protocol to a socket
//
- NewSocketFd = BslSocketProtocolToFd ( pNewSocket, &errno );
- if ( -1 == NewSocketFd ) {
- //
- // Close the socket
- //
- BslSocketCloseWork ( pNewSocket, NULL );
+ if ( !EFI_ERROR ( Status )) {
+ NewSocketFd = BslSocketProtocolToFd ( pNewSocket, &errno );
+ if ( -1 == NewSocketFd ) {
+ //
+ // Close the socket
+ //
+ BslSocketCloseWork ( pNewSocket, NULL );
+ }
}
}
@@ -94,9 +99,10 @@ AcceptWork (
/**
Accept a network connection.
- The ::accept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested. The
+ The accept routine waits for a network connection to the socket.
+ It returns the remote network address to the caller if requested.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html">POSIX</a>
documentation is available online.
@@ -108,8 +114,8 @@ AcceptWork (
of the remote network address buffer. Upon return,
contains the length of the remote network address.
- @return ::accept returns zero if successful and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ @return The accept routine returns zero if successful and -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
@@ -127,9 +133,7 @@ accept (
/**
- Non blocking version of accept.
-
- See ::accept
+ Non blocking version of ::accept.
@param [in] s Socket file descriptor returned from ::socket.
@@ -140,7 +144,7 @@ accept (
contains the length of the remote network address.
@return This routine returns zero if successful and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/bind.c b/StdLib/BsdSocketLib/bind.c
index c1bf64e9e4..f544c94a47 100644
--- a/StdLib/BsdSocketLib/bind.c
+++ b/StdLib/BsdSocketLib/bind.c
@@ -18,9 +18,11 @@
/**
Bind a name to a socket.
- The ::bind routine connects a name to a socket on the local machine. The
+ The bind routine connects a name (network address) to a socket on the local machine.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ documentation is available online.
@param[in] s Socket file descriptor returned from ::socket.
@@ -37,6 +39,7 @@
@param[in] namelen Specifies the length in bytes of the sockaddr structure.
@return The bind routine returns zero (0) if successful and -1 upon failure.
+ In the case of an error, ::errno contains more information.
**/
int
diff --git a/StdLib/BsdSocketLib/close.c b/StdLib/BsdSocketLib/close.c
index 2a9fda4930..3dfeb2bf18 100644
--- a/StdLib/BsdSocketLib/close.c
+++ b/StdLib/BsdSocketLib/close.c
@@ -20,7 +20,7 @@
@param[in] pSocketProtocol Socket protocol structure address
- @param[in] pErrno Address of the errno variable
+ @param[in] pErrno Address of the ::errno variable
@retval EFI_SUCCESS Successfully closed the socket
@@ -83,10 +83,14 @@ BslSocketCloseWork (
/**
Close the socket
+ The BslSocketClose routine is called indirectly from the close file
+ system routine. This routine closes the socket and returns the
+ status to the caller.
+
@param[in] pDescriptor Descriptor address for the file
@return This routine returns 0 upon success and -1 upon failure.
- In the case of failure, errno contains more information.
+ In the case of failure, ::errno contains more information.
**/
int
diff --git a/StdLib/BsdSocketLib/connect.c b/StdLib/BsdSocketLib/connect.c
index 92fc75bdb0..aa4df57d9f 100644
--- a/StdLib/BsdSocketLib/connect.c
+++ b/StdLib/BsdSocketLib/connect.c
@@ -18,11 +18,8 @@
/**
Connect to a remote system via the network.
- The ::connect routine attempts to establish a connection to a
+ The connect routine attempts to establish a connection to a
socket on the local or remote system using the specified address.
- The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">POSIX</a>
- documentation is available online.
There are three states associated with a connection:
<ul>
@@ -30,23 +27,27 @@
<li>Connection in progress</li>
<li>Connected</li>
</ul>
- In the "Not connected" state, calls to ::connect start the connection
+ In the initial "Not connected" state, calls to connect start the connection
processing and update the state to "Connection in progress". During
the "Connection in progress" state, connect polls for connection completion
and moves the state to "Connected" after the connection is established.
Note that these states are only visible when the file descriptor is marked
- with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection
+ with O_NONBLOCK. Also, the POLLOUT bit is set when the connection
completes and may be used by poll or select as an indicator to call
connect again.
+ The
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">POSIX</a>
+ documentation is available online.
+
@param [in] s Socket file descriptor returned from ::socket.
@param [in] address Network address of the remote system
@param [in] address_len Length of the remote network address
- @return ::connect returns zero if successful and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ @return This routine returns zero if successful and -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
@@ -70,9 +71,9 @@ connect (
&errno );
if ( NULL != pSocketProtocol ) {
//
- // TODO: Check for NON_BLOCKING
+ // Determine if the operation is blocking
//
- bBlocking = TRUE;
+ bBlocking = (BOOLEAN)( 0 == ( pDescriptor->Oflags & O_NONBLOCK ));
//
// Attempt to connect to a remote system
diff --git a/StdLib/BsdSocketLib/errno.c b/StdLib/BsdSocketLib/errno.c
index 360609bd80..2f81506b7a 100644
--- a/StdLib/BsdSocketLib/errno.c
+++ b/StdLib/BsdSocketLib/errno.c
@@ -15,4 +15,7 @@
#include <sys/errno.h>
+/**
+ Variable that contains additional error information when an API call fails.
+**/
int errno;
diff --git a/StdLib/BsdSocketLib/getpeername.c b/StdLib/BsdSocketLib/getpeername.c
index 37e6d1eab6..5991099274 100644
--- a/StdLib/BsdSocketLib/getpeername.c
+++ b/StdLib/BsdSocketLib/getpeername.c
@@ -18,7 +18,8 @@
/**
Get the remote address
- The ::getpeername routine retrieves the remote system address from the socket.
+ The getpeername routine retrieves the remote system address from the socket.
+
The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html#">POSIX</a>
documentation is available online.
@@ -29,8 +30,8 @@
@param [in] address_len Length of the remote network address structure
- @return ::getpeername returns zero (0) if successful or -1 when an error occurs.
- In the case of an error, errno contains more details.
+ @return This routine returns zero (0) if successful or -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/getsockname.c b/StdLib/BsdSocketLib/getsockname.c
index e8d1d55bb3..11614493db 100644
--- a/StdLib/BsdSocketLib/getsockname.c
+++ b/StdLib/BsdSocketLib/getsockname.c
@@ -18,7 +18,8 @@
/**
Get the local socket address.
- The ::getsockname routine retrieves the local system address from the socket.
+ The getsockname routine retrieves the local system address from the socket.
+
The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html#">POSIX</a>
documentation is available online.
@@ -29,8 +30,8 @@
@param [in] address_len Length of the local network address structure
- @return ::getsockname returns zero (0) if successful or -1 when an error occurs.
- In the case of an error, errno contains more details.
+ @return This routine returns zero (0) if successful or -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/getsockopt.c b/StdLib/BsdSocketLib/getsockopt.c
index eac10544de..47b7c6fb34 100644
--- a/StdLib/BsdSocketLib/getsockopt.c
+++ b/StdLib/BsdSocketLib/getsockopt.c
@@ -18,6 +18,10 @@
/**
Get the socket options
+ The
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html#">POSIX</a>
+ documentation is available online.
+
@param [in] s Socket file descriptor returned from ::socket.
@param [in] level Option protocol level
@param [in] option_name Name of the option
@@ -25,8 +29,8 @@
@param [in,out] option_len Length of the buffer in bytes,
upon return length of the option value in bytes
- @retval Zero (0) upon success
- @retval Minus one (-1) upon failure, errno set with additional error information
+ @return This routine returns zero (0) if successful or -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/listen.c b/StdLib/BsdSocketLib/listen.c
index 193444a25c..7c6d5f3d39 100644
--- a/StdLib/BsdSocketLib/listen.c
+++ b/StdLib/BsdSocketLib/listen.c
@@ -18,20 +18,23 @@
/**
Establish the known port to listen for network connections.
- The ::listen routine places the port into a state that enables connection
+ The listen routine places the port into a state that enables connection
attempts. Connections are placed into FIFO order in a queue to be serviced
by the application. The application calls the ::accept routine to remove
- the next connection from the queue and get the associated socket. The
+ the next connection from the queue and get the associated socket.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ documentation is available online.
@param [in] s Socket file descriptor returned from ::socket.
@param [in] backlog backlog specifies the maximum FIFO depth for the connections
- waiting for the application to call accept. Connection attempts
+ waiting for the application to call ::accept. Connection attempts
received while the queue is full are refused.
- @return The listen routine returns zero (0) if successful and -1 upon failure.
+ @return This routine returns zero (0) if successful or -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/read.c b/StdLib/BsdSocketLib/read.c
index 6f8d42974b..293c101463 100644
--- a/StdLib/BsdSocketLib/read.c
+++ b/StdLib/BsdSocketLib/read.c
@@ -18,12 +18,18 @@
/**
Read support routine for sockets
+ The BslSocketRead routine is called indirectly by the read file
+ system routine. This routine is typically used for SOCK_STREAM
+ because it waits for receive data from the target system specified
+ in the ::connect call.
+
@param [in] pDescriptor Descriptor address for the file
@param [in] pOffset File offset
@param [in] LengthInBytes Number of bytes to read
@param [in] pBuffer Address of the buffer to receive the data
@return The number of bytes read or -1 if an error occurs.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
diff --git a/StdLib/BsdSocketLib/recv.c b/StdLib/BsdSocketLib/recv.c
index 91f07cb08a..0ad7252c44 100644
--- a/StdLib/BsdSocketLib/recv.c
+++ b/StdLib/BsdSocketLib/recv.c
@@ -18,8 +18,12 @@
/**
Receive data from a network connection.
- The ::recv routine waits for receive data from a remote network
- connection. The
+ The recv routine waits for receive data from a remote network
+ connection. This routine is typically used for SOCK_STREAM
+ because it waits for receive data from the target system specified
+ in the ::connect call.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html">POSIX</a>
documentation is available online.
@@ -31,9 +35,9 @@
@param [in] flags Message control flags
- @return ::recv returns the number of valid bytes in the buffer,
+ @return This routine returns the number of valid bytes in the buffer,
zero if no data was received, and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
diff --git a/StdLib/BsdSocketLib/recvfrom.c b/StdLib/BsdSocketLib/recvfrom.c
index ce230231dc..20b3f4a916 100644
--- a/StdLib/BsdSocketLib/recvfrom.c
+++ b/StdLib/BsdSocketLib/recvfrom.c
@@ -18,8 +18,12 @@
/**
Receive data from a network connection and return the remote system's address.
- The ::recvfrom routine waits for receive data from a remote network
- connection. The
+ The recvfrom routine waits for receive data from a remote network
+ connection. This routine is typically called for SOCK_DGRAM sockets
+ when the socket is being shared by multiple remote systems and it is
+ important to get the remote system address for a response.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html">POSIX</a>
documentation is available online.
@@ -35,9 +39,9 @@
@param [in] address_len Length of the remote network address structure
- @return ::recvfrom returns the number of valid bytes in the buffer,
+ @return This routine returns the number of valid bytes in the buffer,
zero if no data was received, and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
diff --git a/StdLib/BsdSocketLib/res_send.c b/StdLib/BsdSocketLib/res_send.c
index 82addc9745..0b887e79d0 100644
--- a/StdLib/BsdSocketLib/res_send.c
+++ b/StdLib/BsdSocketLib/res_send.c
@@ -767,7 +767,7 @@ read_len:
errno = 0;
fromlen = sizeof(struct sockaddr_in);
resplen = (int)recvfrom(s, (char*)ans, anssiz, 0,
- (struct sockaddr *)&from, &fromlen);
+ (struct sockaddr *)&from, (socklen_t *)&fromlen);
if (resplen <= 0) {
Perror(stderr, "recvfrom", errno);
res_close();
diff --git a/StdLib/BsdSocketLib/send.c b/StdLib/BsdSocketLib/send.c
index 0bbed5ac33..439d8081c1 100644
--- a/StdLib/BsdSocketLib/send.c
+++ b/StdLib/BsdSocketLib/send.c
@@ -18,7 +18,10 @@
/**
Send data using a network connection.
- The ::send routine queues data to the network for transmission.
+ The send routine queues data to the network for transmission.
+ This routine is typically used for SOCK_STREAM sockets where the target
+ system was specified in the ::connect call.
+
The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html">POSIX</a>
documentation is available online.
@@ -31,9 +34,9 @@
@param [in] flags Message control flags
- @return ::send returns the number of data bytes that were
+ @return This routine returns the number of data bytes that were
sent and -1 when an error occurs. In the case of
- an error, errno contains more details.
+ an error, ::errno contains more details.
**/
ssize_t
diff --git a/StdLib/BsdSocketLib/sendto.c b/StdLib/BsdSocketLib/sendto.c
index 5311ce6022..2fb7737c30 100644
--- a/StdLib/BsdSocketLib/sendto.c
+++ b/StdLib/BsdSocketLib/sendto.c
@@ -18,7 +18,11 @@
/**
Send data using a network connection.
- The ::send routine queues data to the network for transmission.
+ The sendto routine queues data to the network for transmission.
+ This routine is typically used for SOCK_DGRAM sockets that are shared
+ between multiple machine where it is required to specify the target
+ system address when sending the data.
+
The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html">POSIX</a>
documentation is available online.
@@ -35,9 +39,9 @@
@param [in] tolen Length of remote system address structure
- @return ::send returns the number of data bytes that were
+ @return This routine returns the number of data bytes that were
sent and -1 when an error occurs. In the case of
- an error, errno contains more details.
+ an error, ::errno contains more details.
**/
ssize_t
@@ -50,6 +54,7 @@ sendto (
socklen_t tolen
)
{
+ BOOLEAN bBlocking;
ssize_t LengthInBytes;
CONST UINT8 * pData;
struct __filedes * pDescriptor;
@@ -69,19 +74,24 @@ sendto (
&errno );
if ( NULL != pSocketProtocol ) {
//
+ // Determine if the operation is blocking
+ //
+ bBlocking = (BOOLEAN)( 0 == ( pDescriptor->Oflags & O_NONBLOCK ));
+
+ //
// Send the data using the socket
//
pData = buffer;
do {
errno = 0;
- Status = pSocketProtocol->pfnSend ( pSocketProtocol,
- flags,
- length,
- pData,
- (size_t *)&LengthInBytes,
- to,
- tolen,
- &errno );
+ Status = pSocketProtocol->pfnTransmit ( pSocketProtocol,
+ flags,
+ length,
+ pData,
+ (size_t *)&LengthInBytes,
+ to,
+ tolen,
+ &errno );
if ( EFI_ERROR ( Status ) && ( EFI_NOT_READY != Status )) {
LengthInBytes = -1;
break;
@@ -92,8 +102,7 @@ sendto (
//
pData += LengthInBytes;
length -= LengthInBytes;
- // TODO: Add non-blocking check
- } while (( 0 != length ) && ( EFI_NOT_READY == Status ));
+ } while (( 0 != length ) && ( EFI_NOT_READY == Status ) && bBlocking );
}
//
diff --git a/StdLib/BsdSocketLib/sethostname.c b/StdLib/BsdSocketLib/sethostname.c
index 7863e8ce45..eb9d914c63 100644
--- a/StdLib/BsdSocketLib/sethostname.c
+++ b/StdLib/BsdSocketLib/sethostname.c
@@ -97,7 +97,7 @@ Returns:
// Create a zero terminated string for name
//
memcpy ( pName, name, namelen );
- pName [ namelen ] = 0;
+ pName[ namelen ] = 0;
//
// Set the environment variable
diff --git a/StdLib/BsdSocketLib/setsockopt.c b/StdLib/BsdSocketLib/setsockopt.c
index 74c948c783..64f3a35911 100644
--- a/StdLib/BsdSocketLib/setsockopt.c
+++ b/StdLib/BsdSocketLib/setsockopt.c
@@ -18,14 +18,18 @@
/**
Set the socket options
+ The
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>
+ documentation is available online.
+
@param [in] s Socket file descriptor returned from ::socket.
@param [in] level Option protocol level
@param [in] option_name Name of the option
@param [in] option_value Buffer containing the option value
@param [in] option_len Length of the value in bytes
- @retval Zero (0) upon success
- @retval Minus one (-1) upon failure, errno set with additional error information
+ @return This routine returns zero (0) upon success and -1 when an error occurs.
+ In the case of an error, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/shutdown.c b/StdLib/BsdSocketLib/shutdown.c
index c3df1ee519..76831a502b 100644
--- a/StdLib/BsdSocketLib/shutdown.c
+++ b/StdLib/BsdSocketLib/shutdown.c
@@ -18,7 +18,8 @@
/**
Shutdown the socket receive and transmit operations
- The ::shutdown routine stops socket receive and transmit operations.
+ The shutdown routine stops socket receive and transmit operations.
+
The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html">POSIX</a>
documentation is available online.
@@ -27,8 +28,8 @@
@param [in] how Which operations to shutdown
- @return ::shutdown returns the zero (0) if successful or -1 when an
- error occurs. In the latter case, errno contains more details.
+ @return This routine returns the zero (0) if successful or -1 when an
+ error occurs. In the latter case, ::errno contains more details.
**/
int
diff --git a/StdLib/BsdSocketLib/socket.c b/StdLib/BsdSocketLib/socket.c
index e78329291c..4f49777b51 100644
--- a/StdLib/BsdSocketLib/socket.c
+++ b/StdLib/BsdSocketLib/socket.c
@@ -15,6 +15,12 @@
#include <SocketInternals.h>
+/**
+ File system interface for the socket layer.
+
+ This data structure defines the routines for the various
+ file system functions associated with the socket layer.
+**/
const struct fileops SocketOperations = {
BslSocketClose, // close
BslSocketRead, // read
@@ -47,7 +53,7 @@ const struct fileops SocketOperations = {
address for the file
@param [in] pErrno Address of the errno variable
- @return A pointer to the socket protocol structure or NULL if
+ @return A pointer to the EFI_SOCKET_PROTOCOL structure or NULL if
an invalid file descriptor was passed in.
**/
@@ -79,7 +85,7 @@ BslFdToSocketProtocol (
//
// Get the descriptor for the file
//
- pDescriptor = &gMD->fdarray [ s ];
+ pDescriptor = &gMD->fdarray[ s ];
//
// Validate that the descriptor is associated with sockets
@@ -125,7 +131,7 @@ BslSocketProtocolToFd (
// Locate a file descriptor
//
FileDescriptor = FindFreeFD ( VALID_CLOSED );
- if( FileDescriptor < 0 ) {
+ if ( FileDescriptor < 0 ) {
//
// All available FDs are in use
//
@@ -135,7 +141,7 @@ BslSocketProtocolToFd (
//
// Initialize the file descriptor
//
- pDescriptor = &gMD->fdarray [ FileDescriptor ];
+ pDescriptor = &gMD->fdarray[ FileDescriptor ];
pDescriptor->f_offset = 0;
pDescriptor->f_flag = 0;
pDescriptor->f_iflags = DTYPE_SOCKET;
@@ -162,28 +168,33 @@ BslSocketProtocolToFd (
/**
Creates an endpoint for network communication.
- The ::Socket routine initializes the communication endpoint by providing
- the support for the socket library function ::socket. The
+ The socket routine initializes the communication endpoint and returns a
+ file descriptor.
+
+ The
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>
- documentation for the socket routine is available online for reference.
+ documentation is available online.
@param [in] domain Select the family of protocols for the client or server
- application.
+ application. The supported values are:
+ <ul>
+ <li>AF_INET - Version 4 UEFI network stack</li>
+ </ul>
@param [in] type Specifies how to make the network connection. The following values
are supported:
<ul>
<li>
- SOCK_STREAM - Connect to TCP, provides a byte stream
- that is manipluated by read, recv, send and write.
+ SOCK_DGRAM - Connect to UDP, provides a datagram service that is
+ manipulated by recvfrom and sendto.
</li>
<li>
- SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream
- that is manipulated by read, recv, send and write.
+ SOCK_STREAM - Connect to TCP, provides a byte stream
+ that is manipluated by read, recv, send and write.
</li>
<li>
- SOCK_DGRAM - Connect to UDP, provides a datagram service that is
- manipulated by recvfrom and sendto.
+ SOCK_RAW - Connect to IP, provides a datagram service that
+ is manipulated by recvfrom and sendto.
</li>
</ul>
@@ -192,9 +203,14 @@ BslSocketProtocolToFd (
<ul>
<li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>
<li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>
+ <li>0 - 254</li> - An assigned
+ <a href="http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml">protocol number</a>
+ is combined with SOCK_RAW.
+ </li>
</ul>
- @return This routine returns a file descriptor for the socket.
+ @return This routine returns a file descriptor for the socket. If an error
+ occurs -1 is returned and ::errno contains more details.
**/
INT32
@@ -226,8 +242,7 @@ socket (
type,
protocol,
&errno );
- if ( !EFI_ERROR ( Status ))
- {
+ if ( !EFI_ERROR ( Status )) {
//
// Build the file descriptor for the socket
//
@@ -250,7 +265,7 @@ socket (
@param [in] pErrno Address of the errno variable
- @return A pointer to the socket protocol structure or NULL if
+ @return A pointer to the EFI_SOCKET_PROTOCOL structure or NULL if
an invalid file descriptor was passed in.
**/
diff --git a/StdLib/BsdSocketLib/write.c b/StdLib/BsdSocketLib/write.c
index f6f50006af..1f8ad004b5 100644
--- a/StdLib/BsdSocketLib/write.c
+++ b/StdLib/BsdSocketLib/write.c
@@ -24,6 +24,7 @@
@param [in] pBuffer Address of the data
@return The number of bytes written or -1 if an error occurs.
+ In the case of an error, ::errno contains more details.
**/
ssize_t
diff --git a/StdLib/EfiSocketLib/DxeSupport.c b/StdLib/EfiSocketLib/DxeSupport.c
new file mode 100644
index 0000000000..284fa9cdfe
--- /dev/null
+++ b/StdLib/EfiSocketLib/DxeSupport.c
@@ -0,0 +1,322 @@
+/** @file
+ SocketDxe support routines
+
+ 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"
+
+
+/**
+ Creates a child handle and installs gEfiSocketProtocolGuid.
+
+ This routine creates a child handle for the socket driver and
+ installs the ::gEfiSocketProtocolGuid on that handle with a pointer
+ to the ::EFI_SOCKET_PROTOCOL structure address.
+
+ This routine is called by ::EslServiceGetProtocol in UseSocketDxe
+ when the socket application is linked with UseSocketDxe.
+
+ @param [in] pThis Address of the EFI_SERVICE_BINDING_PROTOCOL structure.
+ @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
+ the child
+ @retval other The child handle was not created
+
+**/
+EFI_STATUS
+EFIAPI
+EslDxeCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN OUT EFI_HANDLE * pChildHandle
+ )
+{
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Create a socket structure
+ //
+ Status = EslSocketAllocate ( pChildHandle,
+ DEBUG_SOCKET,
+ &pSocket );
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Removes gEfiSocketProtocolGuid and destroys the child handle.
+
+ This routine uninstalls ::gEfiSocketProtocolGuid from the child handle
+ and destroys the child handle if necessary.
+
+ This routine is called from ???.
+
+ @param [in] pThis Address of the EFI_SERVICE_BINDING_PROTOCOL structure.
+ @param [in] ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCESS The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
+ because its services are being used.
+ @retval other The child handle was not destroyed
+
+**/
+EFI_STATUS
+EFIAPI
+EslDxeDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pSocket;
+ ESL_SOCKET * pSocketPrevious;
+ EFI_SOCKET_PROTOCOL * pSocketProtocol;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the socket control structure
+ //
+ pLayer = &mEslLayer;
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiSocketProtocolGuid,
+ (VOID **)&pSocketProtocol,
+ pLayer->ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Walk the socket list
+ //
+ pSocketPrevious = pLayer->pSocketList;
+ if ( NULL != pSocketPrevious ) {
+ if ( pSocket == pSocketPrevious ) {
+ //
+ // Remove the socket from the head of the list
+ //
+ pLayer->pSocketList = pSocket->pNext;
+ }
+ else {
+ //
+ // Find the socket in the middle of the list
+ //
+ while (( NULL != pSocketPrevious )
+ && ( pSocket != pSocketPrevious->pNext )) {
+ //
+ // Set the next socket
+ //
+ pSocketPrevious = pSocketPrevious->pNext;
+ }
+ if ( NULL != pSocketPrevious ) {
+ //
+ // Remove the socket from the middle of the list
+ //
+ pSocketPrevious = pSocket->pNext;
+ }
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Socket list is empty!\r\n" ));
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ //
+ // Determine if the socket was found
+ //
+ if ( NULL != pSocketPrevious ) {
+ pSocket->pNext = NULL;
+
+ //
+ // Remove the socket protocol
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiSocketProtocolGuid,
+ &pSocket->SocketProtocol,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INFO,
+ "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
+ ChildHandle ));
+
+ //
+ // Free the socket structure
+ //
+ Status = gBS->FreePool ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Free pSocket, %d bytes\r\n",
+ pSocket,
+ sizeof ( *pSocket )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
+ pSocket,
+ Status ));
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
+ "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
+ ChildHandle,
+ Status ));
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_INFO,
+ "ERROR - The socket was not in the socket list!\r\n" ));
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",
+ ChildHandle,
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+Install the socket service
+
+This routine installs the ::gEfiSocketServiceBindingProtocolGuid
+on the SocketDxe image handle to announce the availability
+of the socket layer to the rest of EFI.
+
+SocketDxe's EntryPoint routine calls this routine to
+make the socket layer available.
+
+@param [in] pImageHandle Address of the image handle
+
+@retval EFI_SUCCESS Service installed successfully
+**/
+EFI_STATUS
+EFIAPI
+EslDxeInstall (
+ IN EFI_HANDLE * pImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install the socket service binding protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ pImageHandle,
+ &gEfiSocketServiceBindingProtocolGuid,
+ mEslLayer.pServiceBinding,
+ NULL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
+ "Installed: gEfiSocketServiceBindingProtocolGuid on 0x%08x\r\n",
+ *pImageHandle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - InstallMultipleProtocolInterfaces failed, Status: %r\r\n",
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+Uninstall the socket service
+
+This routine removes the gEfiSocketServiceBindingProtocolGuid from
+the SocketDxe image handle to notify EFI that the socket layer
+is no longer available.
+
+SocketDxe's DriverUnload routine calls this routine to remove the
+socket layer.
+
+@param [in] ImageHandle Handle for the image.
+
+@retval EFI_SUCCESS Service installed successfully
+**/
+EFI_STATUS
+EFIAPI
+EslDxeUninstall (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install the socket service binding protocol
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiSocketServiceBindingProtocolGuid,
+ mEslLayer.pServiceBinding,
+ NULL
+ );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL | DEBUG_INIT,
+ "Removed: gEfiSocketServiceBindingProtocolGuid from 0x%08x\r\n",
+ ImageHandle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Failed to remove gEfiSocketServiceBindingProtocolGuid from 0x%08x, Status: %r\r\n",
+ ImageHandle,
+ Status ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
diff --git a/StdLib/EfiSocketLib/EfiSocketLib.inf b/StdLib/EfiSocketLib/EfiSocketLib.inf
index 6671e840f2..df639527f6 100644
--- a/StdLib/EfiSocketLib/EfiSocketLib.inf
+++ b/StdLib/EfiSocketLib/EfiSocketLib.inf
@@ -28,7 +28,9 @@
#
[Sources.common]
+ DxeSupport.c
Init.c
+ Ip4.c
Service.c
Socket.c
Tcp4.c
@@ -43,10 +45,13 @@
[LibraryClasses]
BaseMemoryLib
DebugLib
+ MemoryAllocationLib
UefiBootServicesTableLib
UefiLib
[Protocols]
+ gEfiIp4ProtocolGuid
+ gEfiIp4ServiceBindingProtocolGuid
gEfiTcp4ProtocolGuid
gEfiTcp4ServiceBindingProtocolGuid
gEfiUdp4ProtocolGuid
diff --git a/StdLib/EfiSocketLib/Init.c b/StdLib/EfiSocketLib/Init.c
index f444acc742..88d2065c21 100644
--- a/StdLib/EfiSocketLib/Init.c
+++ b/StdLib/EfiSocketLib/Init.c
@@ -18,7 +18,22 @@
/**
EFI Socket Library Constructor
- @retval EFI_SUCCESS The initialization was successful
+ This routine supports an implementation dependent constructor
+ depending upon whether the library is linked to a socket
+ application or the SocketDxe driver. The following modules
+ declare the redirection for the constructor in ::mpfnEslConstructor:
+ <ul>
+ <li>StdLib/EfiSocketLib/UseSocketLib.c - Application links against EfiSocketLib</li>
+ <li>StdLib/SocketDxe/EntryUnload.c - SocketDxe links against EfiSocketLib</li>
+ </ul>
+
+ The EfiSocketLib.inf file lists ::EslConstructor as the CONSTRUCTOR
+ in the [Defines] section. As a result, this routine is called by
+ the ProcessLibraryConstructorList routine of the AutoGen.c module
+ in the Build directory associated with the socket application or
+ the SocketDxe driver.
+
+ @retval EFI_SUCCESS The socket layer initialization was successful
**/
EFI_STATUS
@@ -54,7 +69,22 @@ EslConstructor (
/**
EFI Socket Library Destructor
- @retval EFI_SUCCESS The shutdown was successful
+ This routine supports an implementation dependent destructor
+ depending upon whether the library is linked to a socket
+ application or the SocketDxe driver. The following modules
+ declare the redirection for the destructor in ::mpfnEslDestructor:
+ <ul>
+ <li>StdLib/EfiSocketLib/UseSocketLib.c - Application links against EfiSocketLib</li>
+ <li>StdLib/SocketDxe/EntryUnload.c - SocketDxe links against EfiSocketLib</li>
+ </ul>
+
+ The EfiSocketLib.inf file lists ::EslDestructor as the DESTRUCTOR
+ in the [Defines] section. As a result, this routine is called by
+ the ProcessLibraryDestructorList routine of the AutoGen.c module
+ in the Build directory associated with the socket application or
+ the SocketDxe driver.
+
+ @retval EFI_SUCCESS The socket layer shutdown was successful
**/
EFI_STATUS
diff --git a/StdLib/EfiSocketLib/Ip4.c b/StdLib/EfiSocketLib/Ip4.c
new file mode 100644
index 0000000000..2d341269cc
--- /dev/null
+++ b/StdLib/EfiSocketLib/Ip4.c
@@ -0,0 +1,1264 @@
+/** @file
+ Implement the IP4 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 IPv4 address associated with the local
+ socket.
+
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_RAW socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @param [out] pAddress Network address to receive the local system address
+
+**/
+VOID
+EslIp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in * pLocalAddress;
+ ESL_IP4_CONTEXT * pIp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pLocalAddress = (struct sockaddr_in *)pAddress;
+ pLocalAddress->sin_family = AF_INET;
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_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 IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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
+EslIp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
+ )
+{
+ EFI_IP4_CONFIG_DATA * pConfig;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
+ //
+ // The local address must not be the broadcast address
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
+ Status = EFI_SUCCESS;
+
+ //
+ // Set the local address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
+ pConfig->StationAddress.Addr[0] = pIpv4Address[0];
+ pConfig->StationAddress.Addr[1] = pIpv4Address[1];
+ pConfig->StationAddress.Addr[2] = pIpv4Address[2];
+ pConfig->StationAddress.Addr[3] = pIpv4Address[3];
+
+ //
+ // Determine if the default address is used
+ //
+ pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local IP4 Address: %d.%d.%d.%d\r\n",
+ pPort,
+ pConfig->StationAddress.Addr[0],
+ pConfig->StationAddress.Addr[1],
+ pConfig->StationAddress.Addr[2],
+ pConfig->StationAddress.Addr[3]));
+
+ //
+ // Set the subnet mask
+ //
+ if ( pConfig->UseDefaultAddress ) {
+ pConfig->SubnetMask.Addr[0] = 0;
+ pConfig->SubnetMask.Addr[1] = 0;
+ pConfig->SubnetMask.Addr[2] = 0;
+ pConfig->SubnetMask.Addr[3] = 0;
+ }
+ else {
+ pConfig->SubnetMask.Addr[0] = 0xff;
+ pConfig->SubnetMask.Addr[1] = 0xff;
+ pConfig->SubnetMask.Addr[2] = 0xff;
+ pConfig->SubnetMask.Addr[3] = 0xff;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Get the option value
+
+ This routine handles the IPv4 level options.
+
+ The ::EslSocketOptionGet routine calls this routine to retrieve
+ the IPv4 options one at a time by name.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [out] ppOptionData Buffer to receive address of option value
+ @param [out] pOptionLength Buffer to receive the option length
+
+ @retval EFI_SUCCESS - Socket data successfully received
+
+ **/
+EFI_STATUS
+EslIp4OptionGet (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ OUT CONST void ** __restrict ppOptionData,
+ OUT socklen_t * __restrict pOptionLength
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Attempt to get the option
+ //
+ switch ( OptionName ) {
+ default:
+ //
+ // Option not supported
+ //
+ pSocket->errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case IP_HDRINCL:
+ *ppOptionData = (void *)pSocket->bIncludeHeader;
+ *pOptionLength = sizeof ( pSocket->bIncludeHeader );
+ break;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Set the option value
+
+ This routine handles the IPv4 level options.
+
+ The ::EslSocketOptionSet routine calls this routine to adjust
+ the IPv4 options one at a time by name.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [in] pOptionValue Buffer containing the option value
+ @param [in] OptionLength Length of the buffer in bytes
+
+ @retval EFI_SUCCESS - Option successfully set
+
+ **/
+EFI_STATUS
+EslIp4OptionSet (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ IN CONST void * pOptionValue,
+ IN socklen_t OptionLength
+ )
+{
+ BOOLEAN bTrueFalse;
+ socklen_t LengthInBytes;
+ UINT8 * pOptionData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the option protocol matches
+ //
+ LengthInBytes = 0;
+ pOptionData = NULL;
+ switch ( OptionName ) {
+ default:
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid protocol option\r\n" ));
+ pSocket->errno = ENOTSUP;
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ case IP_HDRINCL:
+
+ //
+ // Validate the option length
+ //
+ if ( sizeof ( UINT32 ) == OptionLength ) {
+ //
+ // Restrict the input to TRUE or FALSE
+ //
+ bTrueFalse = TRUE;
+ if ( 0 == *(UINT32 *)pOptionValue ) {
+ bTrueFalse = FALSE;
+ }
+ pOptionValue = &bTrueFalse;
+
+ //
+ // Set the option value
+ //
+ pOptionData = (UINT8 *)&pSocket->bIncludeHeader;
+ LengthInBytes = sizeof ( pSocket->bIncludeHeader );
+ }
+ break;
+ }
+
+ //
+ // 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
+EslIp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ EFI_IP4_RECEIVE_DATA * pRxData;
+ DBG_ENTER ( );
+
+ //
+ // Account for the receive bytes
+ //
+ pRxData = pPacket->Op.Ip4Rx.pRxData;
+ *pRxBytes -= pRxData->HeaderLength + pRxData->DataLength;
+
+ //
+ // Disconnect the buffer from the packet
+ //
+ pPacket->Op.Ip4Rx.pRxData = NULL;
+
+ //
+ // Return the buffer to the IP4 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 IPv4 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
+EslIp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_IP4_CONFIG_DATA * pConfig;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Initialize the port
+ //
+ pSocket = pPort->pSocket;
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Ip4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Tx.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_IP4_COMPLETION_TOKEN, Packet.TxData );
+
+ //
+ // Save the cancel, receive and transmit addresses
+ //
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.IPv4->Configure;
+ pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Cancel;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.IPv4->Transmit;
+
+ //
+ // Set the configuration flags
+ //
+ pConfig = &pPort->Context.Ip4.ModeData.ConfigData;
+ pConfig->AcceptIcmpErrors = FALSE;
+ pConfig->AcceptBroadcast = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->TypeOfService = 0;
+ pConfig->TimeToLive = 255;
+ pConfig->DoNotFragment = FALSE;
+ pConfig->RawData = FALSE;
+ pConfig->ReceiveTimeout = 0;
+ pConfig->TransmitTimeout = 0;
+
+ //
+ // Set the default protocol
+ //
+ pConfig->DefaultProtocol = (UINT8)pSocket->Protocol;
+ pConfig->AcceptAnyProtocol = (BOOLEAN)( 0 == pConfig->DefaultProtocol );
+ 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_RAW 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 *
+EslIp4Receive (
+ 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;
+ size_t HeaderBytes;
+ size_t LengthInBytes;
+ struct sockaddr_in * pRemoteAddress;
+ EFI_IP4_RECEIVE_DATA * pRxData;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote system address if requested
+ //
+ pRxData = pPacket->Op.Ip4Rx.pRxData;
+ if ( NULL != pAddress ) {
+ //
+ // Build the remote address
+ //
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d\r\n",
+ pRxData->Header->SourceAddress.Addr[0],
+ pRxData->Header->SourceAddress.Addr[1],
+ pRxData->Header->SourceAddress.Addr[2],
+ pRxData->Header->SourceAddress.Addr[3]));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pRxData->Header->SourceAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ }
+
+ //
+ // Copy the IP header
+ //
+ HeaderBytes = pRxData->HeaderLength;
+ if ( HeaderBytes > BufferLength ) {
+ HeaderBytes = BufferLength;
+ }
+ DEBUG (( DEBUG_RX,
+ "0x%08x --> 0x%08x: Copy header 0x%08x bytes\r\n",
+ pRxData->Header,
+ pBuffer,
+ HeaderBytes ));
+ CopyMem ( pBuffer, pRxData->Header, HeaderBytes );
+ pBuffer += HeaderBytes;
+ LengthInBytes = HeaderBytes;
+
+ //
+ // Copy the received data
+ //
+ if ( 0 < ( BufferLength - LengthInBytes )) {
+ pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
+ &pRxData->FragmentTable[0],
+ BufferLength - LengthInBytes,
+ pBuffer,
+ &DataBytes );
+ LengthInBytes += 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,
+ LengthInBytes ));
+
+ //
+ // Account for any discarded data
+ //
+ *pSkipBytes = pRxData->HeaderLength + pRxData->DataLength - LengthInBytes;
+ }
+
+ //
+ // Return the data length and the buffer address
+ //
+ *pDataLength = LengthInBytes;
+ 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_RAW socket.
+
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the IPv4 address 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
+EslIp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
+ )
+{
+ struct sockaddr_in * pRemoteAddress;
+ ESL_IP4_CONTEXT * pIp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the remote address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pIp4->DestinationAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_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
+EslIp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ ESL_IP4_CONTEXT * pIp4;
+ CONST struct sockaddr_in * pRemoteAddress;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Set the remote address
+ //
+ pIp4 = &pPort->Context.Ip4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pIp4->DestinationAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pIp4->DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pIp4->DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pIp4->DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the receive completion
+
+ This routine keeps the IPv4 driver's buffer and queues it in
+ in FIFO order to the data queue. The IP4 driver's buffer will
+ be returned by either ::EslIp4Receive or ::EslSocketPortCloseTxDone.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by the IPv4 driver when data is
+ received.
+
+ @param [in] Event The receive completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslIp4RxComplete (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ size_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ EFI_IP4_RECEIVE_DATA * pRxData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Get the operation status.
+ //
+ pPort = pIo->pPort;
+ Status = pIo->Token.Ip4Rx.Status;
+
+ //
+ // Get the packet length
+ //
+ pRxData = pIo->Token.Ip4Rx.Packet.RxData;
+ LengthInBytes = pRxData->HeaderLength + pRxData->DataLength;
+
+ //
+ // +--------------------+ +----------------------+
+ // | ESL_IO_MGMT | | Data Buffer |
+ // | | | (Driver owned) |
+ // | +---------------+ +----------------------+
+ // | | Token | ^
+ // | | Rx Event | |
+ // | | | +----------------------+
+ // | | RxData --> | EFI_IP4_RECEIVE_DATA |
+ // +----+---------------+ | (Driver owned) |
+ // +----------------------+
+ // +--------------------+ ^
+ // | ESL_PACKET | .
+ // | | .
+ // | +---------------+ .
+ // | | pRxData --> NULL .......
+ // +----+---------------+
+ //
+ //
+ // Save the data in the packet
+ //
+ pPacket = pIo->pPacket;
+ pPacket->Op.Ip4Rx.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 ::EslSocketBind 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
+ EslIp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ UINTN Index;
+ ESL_PORT * pPort;
+ ESL_PORT * pNextPort;
+ ESL_IP4_CONTEXT * pIp4;
+ EFI_IP4_PROTOCOL * pIp4Protocol;
+ EFI_STATUS Status;
+ struct sockaddr_in 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 ) {
+ LocalAddress.sin_len = sizeof ( LocalAddress );
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_addr.s_addr = 0;
+ LocalAddress.sin_port = 0;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len,
+ &pSocket->errno );
+ }
+
+ //
+ // Walk the port list
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Update the raw setting
+ //
+ pIp4 = &pPort->Context.Ip4;
+ if ( pSocket->bIncludeHeader ) {
+ //
+ // IP header will be included with the data on transmit
+ //
+ pIp4->ModeData.ConfigData.RawData = TRUE;
+ }
+
+ //
+ // Attempt to configure the port
+ //
+ pNextPort = pPort->pLinkSocket;
+ pIp4Protocol = pPort->pProtocol.IPv4;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configuring for %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ pPort,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pIp4->DestinationAddress.Addr[0],
+ pIp4->DestinationAddress.Addr[1],
+ pIp4->DestinationAddress.Addr[2],
+ pIp4->DestinationAddress.Addr[3]));
+ Status = pIp4Protocol->Configure ( pIp4Protocol,
+ &pIp4->ModeData.ConfigData );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Update the configuration data
+ //
+ Status = pIp4Protocol->GetModeData ( pIp4Protocol,
+ &pIp4->ModeData,
+ NULL,
+ NULL );
+ }
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_LISTEN,
+ "ERROR - Failed to configure the Ip4 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 %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ pPort,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pIp4->DestinationAddress.Addr[0],
+ pIp4->DestinationAddress.Addr[1],
+ pIp4->DestinationAddress.Addr[2],
+ pIp4->DestinationAddress.Addr[3]));
+ DEBUG (( DEBUG_TX,
+ "Subnet Mask: %d.%d.%d.%d\r\n",
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[0],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[1],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[2],
+ pIp4->ModeData.ConfigData.SubnetMask.Addr[3]));
+ DEBUG (( DEBUG_TX,
+ "Route Count: %d\r\n",
+ pIp4->ModeData.RouteCount ));
+ for ( Index = 0; pIp4->ModeData.RouteCount > Index; Index++ ) {
+ if ( 0 == Index ) {
+ DEBUG (( DEBUG_TX, "Route Table:\r\n" ));
+ }
+ DEBUG (( DEBUG_TX,
+ "%5d: %d.%d.%d.%d, %d.%d.%d.%d ==> %d.%d.%d.%d\r\n",
+ Index,
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[0],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[1],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[2],
+ pIp4->ModeData.RouteTable[Index].SubnetAddress.Addr[3],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[0],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[1],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[2],
+ pIp4->ModeData.RouteTable[Index].SubnetMask.Addr[3],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[0],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[1],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[2],
+ pIp4->ModeData.RouteTable[Index].GatewayAddress.Addr[3]));
+ }
+ 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
+EslIp4TxBuffer (
+ 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_in * pRemoteAddress;
+ ESL_IP4_CONTEXT * pIp4;
+ size_t * pTxBytes;
+ ESL_IP4_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
+ //
+ pIp4 = &pPort->Context.Ip4;
+ 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.Ip4Tx )
+ - sizeof ( pPacket->Op.Ip4Tx.Buffer )
+ + BufferLength,
+ 0,
+ DEBUG_TX );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Initialize the transmit operation
+ //
+ pTxData = &pPacket->Op.Ip4Tx;
+ pTxData->TxData.DestinationAddress.Addr[0] = pIp4->DestinationAddress.Addr[0];
+ pTxData->TxData.DestinationAddress.Addr[1] = pIp4->DestinationAddress.Addr[1];
+ pTxData->TxData.DestinationAddress.Addr[2] = pIp4->DestinationAddress.Addr[2];
+ pTxData->TxData.DestinationAddress.Addr[3] = pIp4->DestinationAddress.Addr[3];
+ pTxData->TxData.OverrideData = NULL;
+ pTxData->TxData.OptionsLength = 0;
+ pTxData->TxData.OptionsBuffer = NULL;
+ pTxData->TxData.TotalDataLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentCount = 1;
+ pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
+ pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Ip4Tx.Buffer[0];
+
+ //
+ // Set the remote system address if necessary
+ //
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (const struct sockaddr_in *)pAddress;
+ pTxData->Override.SourceAddress.Addr[0] = pIp4->ModeData.ConfigData.StationAddress.Addr[0];
+ pTxData->Override.SourceAddress.Addr[1] = pIp4->ModeData.ConfigData.StationAddress.Addr[1];
+ pTxData->Override.SourceAddress.Addr[2] = pIp4->ModeData.ConfigData.StationAddress.Addr[2];
+ pTxData->Override.SourceAddress.Addr[3] = pIp4->ModeData.ConfigData.StationAddress.Addr[3];
+ pTxData->TxData.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
+ pTxData->TxData.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pTxData->TxData.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pTxData->TxData.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pTxData->Override.GatewayAddress.Addr[0] = 0;
+ pTxData->Override.GatewayAddress.Addr[1] = 0;
+ pTxData->Override.GatewayAddress.Addr[2] = 0;
+ pTxData->Override.GatewayAddress.Addr[3] = 0;
+ pTxData->Override.Protocol = (UINT8)pSocket->Protocol;
+ pTxData->Override.TypeOfService = 0;
+ pTxData->Override.TimeToLive = 255;
+ pTxData->Override.DoNotFragment = FALSE;
+
+ //
+ // Use the remote system address when sending this packet
+ //
+ pTxData->TxData.OverrideData = &pTxData->Override;
+ }
+
+ //
+ // Copy the data into the buffer
+ //
+ CopyMem ( &pPacket->Op.Ip4Tx.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 bytes from 0x%08x, %d.%d.%d.%d --> %d.%d.%d.%d\r\n",
+ BufferLength,
+ pBuffer,
+ pIp4->ModeData.ConfigData.StationAddress.Addr[0],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[1],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[2],
+ pIp4->ModeData.ConfigData.StationAddress.Addr[3],
+ pTxData->TxData.DestinationAddress.Addr[0],
+ pTxData->TxData.DestinationAddress.Addr[1],
+ pTxData->TxData.DestinationAddress.Addr[2],
+ pTxData->TxData.DestinationAddress.Addr[3]));
+
+ //
+ // 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 IPv4 network layer when a data
+ transmit request completes.
+
+ @param [in] Event The normal transmit completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
+
+**/
+VOID
+EslIp4TxComplete (
+ 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.Ip4Tx.TxData.TotalDataLength;
+ pSocket->TxBytes -= LengthInBytes;
+ Status = pIo->Token.Ip4Tx.Status;
+
+ //
+ // Complete the transmit operation
+ //
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Raw ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
+ DBG_EXIT ( );
+}
+
+
+/**
+ Interface between the socket layer and the network specific
+ code that supports SOCK_RAW sockets over IPv4.
+**/
+CONST ESL_PROTOCOL_API cEslIp4Api = {
+ "IPv4",
+ IPPROTO_IP,
+ OFFSET_OF ( ESL_PORT, Context.Ip4.ModeData.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pIp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
+ sizeof (((ESL_PACKET *)0 )->Op.Ip4Rx ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Ip4Rx.Packet.RxData ),
+ FALSE,
+ EADDRNOTAVAIL,
+ NULL, // Accept
+ NULL, // ConnectPoll
+ NULL, // ConnectStart
+ EslIp4SocketIsConfigured,
+ EslIp4LocalAddressGet,
+ EslIp4LocalAddressSet,
+ NULL, // Listen
+ EslIp4OptionGet,
+ EslIp4OptionSet,
+ EslIp4PacketFree,
+ EslIp4PortAllocate,
+ NULL, // PortClose
+ NULL, // PortCloseOp
+ TRUE,
+ EslIp4Receive,
+ EslIp4RemoteAddressGet,
+ EslIp4RemoteAddressSet,
+ EslIp4RxComplete,
+ NULL, // RxStart
+ EslIp4TxBuffer,
+ EslIp4TxComplete,
+ NULL // TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/ReleaseNotes.txt b/StdLib/EfiSocketLib/ReleaseNotes.txt
new file mode 100644
index 0000000000..fd8ed74022
--- /dev/null
+++ b/StdLib/EfiSocketLib/ReleaseNotes.txt
@@ -0,0 +1,31 @@
+The following issues exist with the EFI Socket Library:
+
+* Don't run socket applications or the socket driver for a long time - The IPv4Config
+ and DHCP protocols are not properly running the renew and lease expiration timers.
+ When the DHCP lease expires it is possible for a duplicate IP address to exist on
+ the network. HSD 206136
+
+* Network adapters must be initialized prior to running the socket application - Static
+ and dynamic IP address need to be properly assigned to the network adapters on the
+ system. Note that sockets does not assign the IP addresses since it does not
+ understand how the system is connected to the network!
+
+* The default device must contain the Efi\etc directory populated with files containing
+ the proper network configuration - A template set of files is in StdLib\Efi\etc. Note
+ that the resolv.conf file contains the set of DNS servers.
+
+* Since DHCP is not running when the sockets application is running, the last negotiated
+ packet is no longer available. As a result, any of the options that DHCP did negotiate
+ are no longer available for sockets such as the list of DNS servers.
+
+* DHCP does not request the domain name and domain name server (DNS) addresses. This
+ requires that sockets use configuration files in Efi\etc!
+
+* TCPv4 transfer rate is slow (< 10 Mbits/sec) - This is an unidentified issue.
+
+* Raw socket applications are not able to pass the IP header as part of their
+ payload by using the IP option IP_HDRINCL. This is because the UEFI IPv4 driver
+ (Ip4Dxe) does not support RawData. HSD 206136
+
+* Only version 4 of the UEFI network stack is supported
+
diff --git a/StdLib/EfiSocketLib/Service.c b/StdLib/EfiSocketLib/Service.c
index 49c8884612..927f0e45b4 100644
--- a/StdLib/EfiSocketLib/Service.c
+++ b/StdLib/EfiSocketLib/Service.c
@@ -14,15 +14,16 @@
#include "Socket.h"
-EFI_TCP4_PROTOCOL * mpEfiTcpClose4 [ 1024 ];
-
/**
Connect to the network service bindings
Walk the network service protocols on the controller handle and
- locate any that are not in use. Create service structures to
- manage the service binding for the socket driver.
+ locate any that are not in use. Create ::ESL_SERVICE structures to
+ manage the network layer interfaces for the socket driver. Tag
+ each of the network interfaces that are being used. Finally, this
+ routine calls ESL_SOCKET_BINDING::pfnInitialize to prepare the network
+ interface for use by the socket layer.
@param [in] BindingHandle Handle for protocol binding.
@param [in] Controller Handle of device to work with.
@@ -40,11 +41,13 @@ EslServiceConnect (
{
BOOLEAN bInUse;
UINTN LengthInBytes;
- CONST DT_SOCKET_BINDING * pEnd;
+ UINT8 * pBuffer;
+ CONST ESL_SOCKET_BINDING * pEnd;
VOID * pJunk;
- VOID * pInterface;
- DT_SERVICE * pService;
- CONST DT_SOCKET_BINDING * pSocketBinding;
+ ESL_SERVICE ** ppServiceListHead;
+ ESL_SERVICE * pService;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -68,7 +71,7 @@ EslServiceConnect (
Status = gBS->OpenProtocol (
Controller,
pSocketBinding->pNetworkBinding,
- &pInterface,
+ (VOID**)&pServiceBinding,
BindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -108,7 +111,7 @@ EslServiceConnect (
pService->Signature = SERVICE_SIGNATURE;
pService->pSocketBinding = pSocketBinding;
pService->Controller = Controller;
- pService->pInterface = pInterface;
+ pService->pServiceBinding = pServiceBinding;
//
// Mark the controller in use
@@ -154,9 +157,13 @@ EslServiceConnect (
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Initialize the service
+ // Connect the service to the list
//
- Status = pSocketBinding->pfnInitialize ( pService );
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pSocketBinding->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pService->pNext = *ppServiceListHead;
+ *ppServiceListHead = pService;
//
// Release the socket layer synchronization
@@ -253,12 +260,13 @@ EslServiceConnect (
/**
- Shutdown the network connections to this controller by removing
- NetworkInterfaceIdentifier protocol and closing the DevicePath
- and PciIo protocols on Controller.
+ Shutdown the connections to the network layer by locating the
+ tags on the network interfaces established by ::EslServiceConnect.
+ This routine shutdowns any activity on the network interface and
+ then frees the ::ESL_SERVICE structures.
@param [in] BindingHandle Handle for protocol binding.
- @param [in] Controller Handle of device to stop driver on.
+ @param [in] Controller Handle of device to stop driver on.
@retval EFI_SUCCESS This driver is removed Controller.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
@@ -272,9 +280,13 @@ EslServiceDisconnect (
IN EFI_HANDLE Controller
)
{
- CONST DT_SOCKET_BINDING * pEnd;
- DT_SERVICE * pService;
- CONST DT_SOCKET_BINDING * pSocketBinding;
+ UINT8 * pBuffer;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ ESL_PORT * pPort;
+ ESL_SERVICE * pPreviousService;
+ ESL_SERVICE * pService;
+ ESL_SERVICE ** ppServiceListHead;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -310,9 +322,54 @@ EslServiceDisconnect (
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Shutdown the service
+ // Walk the list of ports
//
- pSocketBinding->pfnShutdown ( pService );
+ pPort = pService->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Remove the port from the port list
+ //
+ pPort->pService = NULL;
+ pService->pPortList = pPort->pLinkService;
+
+ //
+ // Close the port
+ //
+ EslSocketPortCloseStart ( pPort,
+ TRUE,
+ DEBUG_POOL | DEBUG_INIT );
+
+ //
+ // Set the next port
+ //
+ pPort = pService->pPortList;
+ }
+
+ //
+ // Remove the service from the service list
+ //
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pService->pSocketBinding->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pPreviousService = *ppServiceListHead;
+ if ( pService == pPreviousService ) {
+ //
+ // Remove the service from the beginning of the list
+ //
+ *ppServiceListHead = pService->pNext;
+ }
+ else {
+ //
+ // Remove the service from the middle of the list
+ //
+ while ( NULL != pPreviousService ) {
+ if ( pService == pPreviousService->pNext ) {
+ pPreviousService->pNext = pService->pNext;
+ break;
+ }
+ pPreviousService = pPreviousService->pNext;
+ }
+ }
//
// Release the socket layer synchronization
@@ -388,48 +445,6 @@ EslServiceDisconnect (
/**
-Install the socket service
-
-@param [in] pImageHandle Address of the image handle
-
-@retval EFI_SUCCESS Service installed successfully
-**/
-EFI_STATUS
-EFIAPI
-EslServiceInstall (
- IN EFI_HANDLE * pImageHandle
- )
-{
- EFI_STATUS Status;
-
- //
- // Install the socket service binding protocol
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- pImageHandle,
- &gEfiSocketServiceBindingProtocolGuid,
- &mEslLayer.ServiceBinding,
- NULL
- );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
- "Installed: gEfiSocketServiceBindingProtocolGuid on 0x%08x\r\n",
- *pImageHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
- "ERROR - InstallMultipleProtocolInterfaces failed, Status: %r\r\n",
- Status ));
- }
-
- //
- // Return the operation status
- //
- return Status;
-}
-
-
-/**
Initialize the service layer
@param [in] ImageHandle Handle for the image.
@@ -441,69 +456,20 @@ EslServiceLoad (
IN EFI_HANDLE ImageHandle
)
{
- DT_LAYER * pLayer;
+ ESL_LAYER * pLayer;
//
// Save the image handle
//
pLayer = &mEslLayer;
+ ZeroMem ( pLayer, sizeof ( *pLayer ));
pLayer->Signature = LAYER_SIGNATURE;
pLayer->ImageHandle = ImageHandle;
//
- // Initialize the TCP4 close
- //
- pLayer->TcpCloseMax4 = DIM ( mpEfiTcpClose4 );
- pLayer->ppTcpClose4 = mpEfiTcpClose4;
-
- //
// Connect the service binding protocol to the image handle
//
- pLayer->ServiceBinding.CreateChild = EslSocketCreateChild;
- pLayer->ServiceBinding.DestroyChild = EslSocketDestroyChild;
-}
-
-
-/**
-Uninstall the socket service
-
-@param [in] ImageHandle Handle for the image.
-
-@retval EFI_SUCCESS Service installed successfully
-**/
-EFI_STATUS
-EFIAPI
-EslServiceUninstall (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
-
- //
- // Install the socket service binding protocol
- //
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ImageHandle,
- &gEfiSocketServiceBindingProtocolGuid,
- &mEslLayer.ServiceBinding,
- NULL
- );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INIT,
- "Removed: gEfiSocketServiceBindingProtocolGuid from 0x%08x\r\n",
- ImageHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to remove gEfiSocketServiceBindingProtocolGuid from 0x%08x, Status: %r\r\n",
- ImageHandle,
- Status ));
- }
-
- //
- // Return the operation status
- //
- return Status;
+ pLayer->pServiceBinding = &mEfiServiceBinding;
}
@@ -517,13 +483,12 @@ EslServiceUnload (
VOID
)
{
- DT_LAYER * pLayer;
+ ESL_LAYER * pLayer;
//
// Undo the work by ServiceLoad
//
pLayer = &mEslLayer;
pLayer->ImageHandle = NULL;
- pLayer->ServiceBinding.CreateChild = NULL;
- pLayer->ServiceBinding.DestroyChild = NULL;
+ pLayer->pServiceBinding = NULL;
}
diff --git a/StdLib/EfiSocketLib/Socket.c b/StdLib/EfiSocketLib/Socket.c
index ebbc8df4d2..42e4689d0b 100644
--- a/StdLib/EfiSocketLib/Socket.c
+++ b/StdLib/EfiSocketLib/Socket.c
@@ -14,6 +14,446 @@
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 DataStructures Data Structures
+
+ <code><pre>
+
+ +-------------+ +-------------+ +-------------+
+ Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
+ +-------------+ +-------------+ +-------------+
+ ^ | (pPortList) |
+ pUdp4List ^ | pTcp4List | |
+ | | | |
+ ^ | | | |
+ pIp4List | | | | |
+ +---------------+ | |
+ | ::ESL_LAYER | ::mEslLayer | |
+ +---------------+ | |
+ | (pSocketList) | |
+ Socket List V V V
+ +-------------+ +-------------+ +-------------+
+ | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
+ +-------------+ +-------------+ +-------------+
+ | | |
+ | | V
+ V V NULL
+ +-------------+ +-------------+
+ | ESL_SOCKET |-->| ESL_PORT |--> NULL
+ +-------------+ +-------------+
+ | | | | | |
+ V | | | | V
+ NULL | | | | NULL
+ (pNext) | | | | (pLinkService)
+ | | | | pRxPacketListHead
+ | | | `-----------------------------------------------.
+ | | | pRxOobPacketListHead |
+ | | `--------------------------------. |
+ | | pTxPacketListHead | |
+ | `---------------. | |
+ pTxOobPacketListHead | | | |
+ V V V V
+ +------------+ +------------+ +------------+ +------------+
+ | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
+ +------------+ +------------+ +------------+ +------------+
+ | | | |
+ V V V V
+ +------------+ +------------+ +------------+ +------------+
+ | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
+ +------------+ +------------+ +------------+ +------------+
+ | | | |
+ V V V V
+ NULL NULL NULL NULL
+ (pNext)
+
+ </pre></code>
+
+ ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
+ indirectly to the other data structures. The ESL_LAYER structure has a unique
+ service list for each of the network protocol interfaces.
+
+ ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
+
+ ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
+ the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
+ reference and the API into the EFI socket library.
+
+ ::ESL_PORT manages the connection with a single instance of the lower layer network.
+ This structure is the socket equivalent of an IP connection or a TCP or UDP port.
+
+ ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
+ to the ::ESL_SOCKET that manage the data:
+ <ul>
+ <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
+ <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
+ <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
+ <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
+ </ul>
+ The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
+ request as well as the socket option SO_OOBINLINE. The receive queue is selected by
+ the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
+
+ Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
+ critical elements within the data structures must be done at this TPL. TPL is then
+ restored to the previous level. Note that the code verifies that all callbacks are
+ entering at TPL_SOCKETS for proper data structure synchronization.
+
+ \section PortCloseStateMachine Port Close State Machine
+
+ The port close state machine walks the port through the necessary
+ states to stop activity on the port and get it into a state where
+ the resources may be released. The state machine consists of the
+ following arcs and states:
+
+ <code><pre>
+
+ +--------------------------+
+ | Open |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseStart
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_STARTED |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseTxDone
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_TX_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseComplete
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortCloseRxDone
+ V
+ +--------------------------+
+ | PORT_STATE_CLOSE_RX_DONE |
+ +--------------------------+
+ |
+ | ::EslSocketPortClose
+ V
+ +--------------------------+
+ | Closed |
+ +--------------------------+
+
+ </pre></code>
+
+ <ul>
+ <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
+ initiates the port close operation</li>
+ <li>State: PORT_STATE_CLOSE_STARTED</li>
+ <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
+ operations to complete. After all of the transmits are complete,
+ this routine initiates the network specific close operation by calling
+ through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
+ ::EslTcp4PortCloseOp.
+ </li>
+ <li>State: PORT_STATE_CLOSE_TX_DONE</li>
+ <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
+ complete. After the transition to PORT_STATE_CLOSE_DONE,
+ this routine calls ::EslSocketRxCancel to abort the pending receive operations.
+ </li>
+ <li>State: PORT_STATE_CLOSE_DONE</li>
+ <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
+ operation have been cancelled. After the transition to
+ PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
+ </li>
+ <li>State: PORT_STATE_CLOSE_RX_DONE</li>
+ <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
+ using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
+ This routine then releases the port resources allocated by ::EslSocketPortAllocate
+ and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
+ via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
+ </li>
+ </ul>
+
+
+ \section ReceiveEngine Receive Engine
+
+ The receive path accepts data from the network and queues (buffers) it for the
+ application. Flow control is applied once a maximum amount of buffering is reached
+ and is released when the buffer usage drops below that limit. Eventually the
+ application requests data from the socket which removes entries from the queue and
+ returns the data.
+
+ The receive engine is the state machine which reads data from the network and
+ fills the queue with received packets. The receive engine uses two data structures
+ to manage the network receive opeations and the buffers.
+
+ At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
+ events for the interface to the UEFI network stack. The ::ESL_PACKET
+ structures are managing the receive data buffers. The receive engine
+ connects these two structures in the network specific receive completion
+ routines.
+
+<code><pre>
+
+ +------------------+
+ | ::ESL_PORT |
+ | |
+ +------------------+
+ | ::ESL_IO_MGMT |
+ +------------------+
+ | ESL_IO_MGMT |
+ +------------------+
+ . .
+ . ESL_IO_MGMT .
+ . .
+ +------------------+
+
+</pre></code>
+
+ The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
+ ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
+ the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
+ the network layer specific receive completion token and event. The receive engine
+ is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
+ structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
+
+<code><pre>
+
+ pPort->pRxActive
+ |
+ V
+ +-------------+ +-------------+ +-------------+
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+
+ +-------------+ +-------------+ +-------------+
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+ ^
+ |
+ pPort->pRxFree
+</pre></code>
+
+ The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
+ the receive engine by stopping the calls to EslSocketRxStart when the amount of
+ receive data waiting for the application meets or exceeds MAX_RX_DATA. After
+ the application reads enough data that the amount of buffering drops below this
+ limit, the calls to EslSockeRxStart continue which releases the flow control.
+
+ Receive flow control is applied when the port is created, since no receive
+ operation are pending to the low layer network driver. The flow control gets
+ released when the low layer network port is configured or the first receive
+ operation is posted. Flow control remains in the released state until the
+ maximum buffer space is consumed. During this time, ::EslSocketRxComplete
+ calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
+ by skipping the call to EslSocketRxStart. Flow control is eventually
+ released in ::EslSocketReceive when the buffer space drops below the
+ maximum amount causing EslSocketReceive to call EslSocketRxStart.
+
+<code><pre>
+
+ +------------+ +------------+
+ High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
+ Priority | +------------+ +------------+
+ |
+ | pRxOobPacketListHead
+ +------------+
+ | ::ESL_SOCKET |
+ +------------+
+ | pRxPacketListHead
+ Low |
+ Priority | +------------+ +------------+ +------------+
+ `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ +------------+ +------------+ +------------+
+
+</pre></code>
+
+ ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
+ and then calls the network layer to start the receive operation. Upon
+ receive completion, ::EslSocketRxComplete breaks the connection between these
+ structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
+ make token and event available for another receive operation. EslSocketRxComplete
+ then queues the ESL_PACKET structure (data packet) to either the
+ ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
+ whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
+ to start another receive operation.
+
+<code><pre>
+
+ Setup for IP4 and UDP4
+
+ +--------------------+
+ | ESL_IO_MGMT |
+ | |
+ | +---------------+
+ | | Token |
+ | | RxData --> NULL
+ +----+---------------+
+ |
+ V
+ +--------------------+
+ | ESL_PACKET |
+ | |
+ | +---------------+
+ | | pRxData --> NULL
+ +----+---------------+
+
+ Completion for IP4 and UDP4
+
+ +--------------------+ +----------------------+
+ | ESL_IO_MGMT | | Data Buffer |
+ | | | (Driver owned) |
+ | +---------------+ +----------------------+
+ | | Token | ^
+ | | Rx Event | |
+ | | | +----------------------+
+ | | RxData --> | EFI_IP4_RECEIVE_DATA |
+ +----+---------------+ | (Driver owned) |
+ | +----------------------+
+ V ^
+ +--------------------+ .
+ | ESL_PACKET | .
+ | | .
+ | +---------------+ .
+ | | pRxData --> NULL .......
+ +----+---------------+
+
+
+ Setup and completion for TCP4
+
+ +--------------------+ +--------------------------+
+ | ESL_IO_MGMT |-->| ESL_PACKET |
+ | | | |
+ | +---------------+ +----------------------+ |
+ | | Token | | EFI_IP4_RECEIVE_DATA | |
+ | | RxData --> | | |
+ | | | +----------------------+---+
+ | | Event | | Data Buffer |
+ +----+---------------+ | |
+ | |
+ +--------------------------+
+
+</pre></code>
+
+ To minimize the number of buffer copies, the data is not copied until the
+ application makes a receive call. At this point socket performs a single copy
+ in the receive path to move the data from the buffer filled by the network layer
+ into the application's buffer.
+
+ The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
+ allow the socket layer to hold on to the actual receive buffer until the
+ application has performed a receive operation or closes the socket. Both
+ of theses operations return the buffer to the lower layer network driver
+ by calling ESL_PROTOCOL_API::pfnPacketFree.
+
+ When a socket application wants to receive data it indirectly calls
+ ::EslSocketReceive to remove data from one of the receive data queues. This routine
+ removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
+ ESL_SOCKET::pRxPacketListHead and copies the data from the packet
+ into the application's buffer. For SOCK_STREAM sockets, if the packet
+ contains more data then the ESL_PACKET structures remains at the head of the
+ receive queue for the next application receive
+ operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
+ structure is removed from the head of the receive queue and any remaining data is
+ discarded as the packet is placed on the free queue.
+
+ During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
+ cancel any pending receive operations. EslSocketRxCancel calls the network specific
+ cancel routine using ESL_PORT::pfnRxCancel.
+
+
+ \section TransmitEngine Transmit Engine
+
+ Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
+ The buffer exists as an extension to an ESL_PACKET structure and the structure
+ is placed at the end of the transmit queue.
+
+<code><pre>
+
+ *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
+ |
+ V
+ +------------+ +------------+ +------------+
+ Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ +------------+ +------------+ +------------+
+ ^
+ |
+ *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
+
+</pre></code>
+
+ There are actually two transmit queues the normal or low priority queue which is
+ the default and the urgent or high priority queue which is addressed by specifying
+ the MSG_OOB flag during the transmit request. Associated with each queue is a
+ transmit engine which is responsible for sending the data in that queue.
+
+ The transmit engine is the state machine which removes entries from the head
+ of the transmit queue and causes the data to be sent over the network.
+
+<code><pre>
+
+ +--------------------+ +--------------------+
+ | ESL_IO_MGMT | | ESL_PACKET |
+ | | | |
+ | +---------------+ +----------------+ |
+ | | Token | | Buffer Length | |
+ | | TxData --> | Buffer Address | |
+ | | | +----------------+---+
+ | | Event | | Data Buffer |
+ +----+---------------+ | |
+ +--------------------+
+</pre></code>
+
+ At a high level, the transmit engine uses a couple of data structures
+ to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
+ events for the interface to the UEFI network stack. The ::ESL_PACKET
+ structures manage the data buffers that get sent. The transmit
+ engine connects these two structures prior to transmission and disconnects
+ them upon completion.
+
+<code><pre>
+
+ pPort->pTxActive or pTxOobActive
+ |
+ V
+ +-------------+ +-------------+ +-------------+
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+
+ +-------------+ +-------------+ +-------------+
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ +-------------+ +-------------+ +-------------+
+ ^
+ |
+ pPort->pTxFree or pTxOobFree
+
+</pre></code>
+
+ The transmit engine manages multiple transmit operations using the
+ active and free lists shown above. ::EslSocketPortAllocate allocates the
+ ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
+ This routine places the ESL_IO_MGMT structures on the free list by calling
+ ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
+ will move from the free list to the active list and back again. The
+ active list contains the packets that are actively being processed by
+ the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
+ removed from the free list and be deallocated by the EslSocketPortClose
+ routine.
+
+ The network specific code calls the ::EslSocketTxStart routine
+ to hand a packet to the network stack. EslSocketTxStart connects
+ the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
+ and then queues the result to one of the active lists:
+ ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
+ hands the packet to the network stack.
+
+ Upon completion, the network specific TxComplete routine calls
+ ::EslSocketTxComplete to disconnect the transmit packet from the
+ ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
+ ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
+ into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
+ EslSocketTxComplete then starts the next transmit operation while
+ the socket is active or calls the ::EslSocketPortCloseTxDone routine
+ when the socket is shutting down.
+
**/
#include "Socket.h"
@@ -24,62 +464,92 @@
List the network stack connection points for the socket driver.
**/
-CONST DT_SOCKET_BINDING cEslSocketBinding [] = {
+CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
+ { L"Ip4",
+ &gEfiIp4ServiceBindingProtocolGuid,
+ &gEfiIp4ProtocolGuid,
+ &mEslIp4ServiceGuid,
+ OFFSET_OF ( ESL_LAYER, pIp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 0 }, // TX Oob buffers
{ L"Tcp4",
&gEfiTcp4ServiceBindingProtocolGuid,
+ &gEfiTcp4ProtocolGuid,
&mEslTcp4ServiceGuid,
- EslTcpInitialize4,
- EslTcpShutdown4 },
+ OFFSET_OF ( ESL_LAYER, pTcp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 4 }, // TX Oob buffers
{ L"Udp4",
&gEfiUdp4ServiceBindingProtocolGuid,
+ &gEfiUdp4ProtocolGuid,
&mEslUdp4ServiceGuid,
- EslUdpInitialize4,
- EslUdpShutdown4 }
+ OFFSET_OF ( ESL_LAYER, pUdp4List ),
+ 4, // RX buffers
+ 4, // TX buffers
+ 0 } // TX Oob buffers
};
CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
-DT_LAYER mEslLayer;
+/**
+ APIs to support the various socket types for the v4 network stack.
+**/
+CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {
+ NULL, // 0
+ &cEslTcp4Api, // SOCK_STREAM
+ &cEslUdp4Api, // SOCK_DGRAM
+ &cEslIp4Api, // SOCK_RAW
+ NULL, // SOCK_RDM
+ &cEslTcp4Api // SOCK_SEQPACKET
+};
+
+/**
+ Number of entries in the v4 API array ::cEslAfInetApi.
+**/
+CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
+
+
+/**
+ APIs to support the various socket types for the v6 network stack.
+**/
+CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
+ NULL, // 0
+ NULL, // SOCK_STREAM
+ NULL, // SOCK_DGRAM
+ NULL, // SOCK_RAW
+ NULL, // SOCK_RDM
+ NULL // SOCK_SEQPACKET
+};
+
+/**
+ Number of entries in the v6 API array ::cEslAfInet6Api.
+**/
+CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
+
+
+/**
+ Global management structure for the socket layer.
+**/
+ESL_LAYER mEslLayer;
/**
Initialize an endpoint for network communication.
- The ::Socket routine initializes the communication endpoint by providing
- the support for the socket library function ::socket. The
- <a href="http://www.linuxhowtos.org/manpages/2/socket.htm">Linux</a>,
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>
- and <a href="http://msdn.microsoft.com/en-us/library/ms740506(v=VS.85).aspx">Windows</a>
- documentation for the socket routine are available online for reference.
+ This routine initializes the communication endpoint.
+
+ The ::socket routine calls this routine indirectly to create
+ the communication endpoint.
@param [in] pSocketProtocol Address of the socket protocol structure.
@param [in] domain Select the family of protocols for the client or server
- application.
-
- @param [in] type Specifies how to make the network connection. The following values
- are supported:
- <ul>
- <li>
- SOCK_STREAM - Connect to TCP, provides a byte stream
- that is manipluated by read, recv, send and write.
- </li>
- <li>
- SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream
- that is manipulated by read, recv, send and write.
- </li>
- <li>
- SOCK_DGRAM - Connect to UDP, provides a datagram service that is
- manipulated by recvfrom and sendto.
- </li>
- </ul>
-
- @param [in] protocol Specifies the lower layer protocol to use. The following
- values are supported:
- <ul>
- <li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>
- <li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>
- </ul>
-
+ application. See the ::socket documentation for values.
+ @param [in] type Specifies how to make the network connection.
+ See the ::socket documentation for values.
+ @param [in] protocol Specifies the lower layer protocol to use.
+ See the ::socket documentation for values.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket successfully created
@@ -97,7 +567,11 @@ EslSocket (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ CONST ESL_PROTOCOL_API * pApi;
+ CONST ESL_PROTOCOL_API ** ppApiArray;
+ CONST ESL_PROTOCOL_API ** ppApiArrayEnd;
+ int ApiArraySize;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
int errno;
@@ -129,16 +603,30 @@ EslSocket (
// Validate the domain value
//
if (( AF_INET != domain )
- && ( AF_LOCAL != domain ))
- {
+ && ( AF_LOCAL != domain )) {
DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid domain value" ));
+ "ERROR - Invalid domain value\r\n" ));
Status = EFI_INVALID_PARAMETER;
errno = EAFNOSUPPORT;
break;
}
//
+ // Determine the protocol APIs
+ //
+ ppApiArray = NULL;
+ ApiArraySize = 0;
+ if (( AF_INET == domain )
+ || ( AF_LOCAL == domain )) {
+ ppApiArray = &cEslAfInetApi[0];
+ ApiArraySize = cEslAfInetApiSize;
+ }
+ else {
+ ppApiArray = &cEslAfInet6Api[0];
+ ApiArraySize = cEslAfInet6ApiSize;
+ }
+
+ //
// Set the default type if necessary
//
if ( 0 == type ) {
@@ -148,46 +636,81 @@ EslSocket (
//
// Validate the type value
//
- if (( SOCK_STREAM == type )
- || ( SOCK_SEQPACKET == type )) {
- //
- // Set the default protocol if necessary
- //
- if ( 0 == protocol ) {
- protocol = IPPROTO_TCP;
- }
- }
- else if ( SOCK_DGRAM == type ) {
+ if (( type >= ApiArraySize )
+ || ( NULL == ppApiArray )
+ || ( NULL == ppApiArray[ type ])) {
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - Invalid type value\r\n" ));
//
- // Set the default protocol if necessary
+ // The socket type is not supported
//
- if ( 0 == protocol ) {
- protocol = IPPROTO_UDP;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid type value" ));
Status = EFI_INVALID_PARAMETER;
- errno = EINVAL;
+ errno = EPROTOTYPE;
break;
}
//
+ // Set the default protocol if necessary
+ //
+ pApi = ppApiArray[ type ];
+ if ( 0 == protocol ) {
+ protocol = pApi->DefaultProtocol;
+ }
+
+ //
// Validate the protocol value
//
- if (( IPPROTO_TCP != protocol )
- && ( IPPROTO_UDP != protocol )) {
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
- "ERROR - Invalid protocol value" ));
+ if (( pApi->DefaultProtocol != protocol )
+ && ( SOCK_RAW != type )) {
Status = EFI_INVALID_PARAMETER;
- errno = EINVAL;
+
+ //
+ // Assume that the driver supports this protocol
+ //
+ ppApiArray = &cEslAfInetApi[0];
+ ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];
+ while ( ppApiArrayEnd > ppApiArray ) {
+ pApi = *ppApiArray;
+ if ( protocol == pApi->DefaultProtocol ) {
+ break;
+ }
+ ppApiArray += 1;
+ }
+ if ( ppApiArrayEnd <= ppApiArray ) {
+ //
+ // Verify against the IPv6 table
+ //
+ ppApiArray = &cEslAfInet6Api[0];
+ ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];
+ while ( ppApiArrayEnd > ppApiArray ) {
+ pApi = *ppApiArray;
+ if ( protocol == pApi->DefaultProtocol ) {
+ break;
+ }
+ ppApiArray += 1;
+ }
+ }
+ if ( ppApiArrayEnd <= ppApiArray ) {
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - The protocol is not supported!\r\n" ));
+ errno = EPROTONOSUPPORT;
+ break;
+ }
+
+ //
+ // The driver does not support this protocol
+ //
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
+ "ERROR - The protocol does not support this socket type!\r\n" ));
+ errno = EPROTONOSUPPORT;
+ errno = EPROTOTYPE;
break;
}
//
// Save the socket attributes
//
+ pSocket->pApi = pApi;
pSocket->Domain = domain;
pSocket->Type = type;
pSocket->Protocol = protocol;
@@ -212,11 +735,16 @@ EslSocket (
/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
+ This routine calls the network specific layer to remove the next
+ connection from the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::accept calls this routine to poll for a network
+ connection to the socket. When a connection is available
+ this routine returns the ::EFI_SOCKET_PROTOCOL structure address
+ associated with the new socket and the remote network address
+ if requested.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a buffer to receive the remote
network address.
@@ -225,8 +753,9 @@ EslSocket (
On output specifies the length of the
remote network address.
- @param [out] ppSocketProtocol Address of a buffer to receive the socket protocol
- instance associated with the new socket.
+ @param [out] ppSocketProtocol Address of a buffer to receive the
+ ::EFI_SOCKET_PROTOCOL instance
+ associated with the new socket.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -243,8 +772,8 @@ EslSocketAccept (
IN int * pErrno
)
{
- DT_SOCKET * pNewSocket;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pNewSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -264,134 +793,122 @@ EslSocketAccept (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Validate the sockaddr
+ // Verify the API
//
- if (( NULL != pSockAddr )
- && ( NULL == pSockAddrLength )) {
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - pSockAddr is NULL!\r\n" ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EFAULT;
+ if ( NULL == pSocket->pApi->pfnAccept ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
}
else {
//
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ // Validate the sockaddr
//
- // Verify that the socket is in the listen state
- //
- if ( SOCKET_STATE_LISTENING != pSocket->State ) {
+ if (( NULL != pSockAddr )
+ && ( NULL == pSockAddrLength )) {
DEBUG (( DEBUG_ACCEPT,
- "ERROR - Socket is not listening!\r\n" ));
- Status = EFI_NOT_STARTED;
- pSocket->errno = EOPNOTSUPP;
+ "ERROR - pSockAddr is NULL!\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EFAULT;
}
else {
//
- // Determine if a socket is available
+ // Synchronize with the socket layer
//
- if ( 0 == pSocket->FifoDepth ) {
- //
- // No connections available
- // Determine if any ports are available
- //
- if ( NULL == pSocket->pPortList ) {
- //
- // No ports available
- //
- Status = EFI_DEVICE_ERROR;
- pSocket->errno = EINVAL;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ //
+ // Verify that the socket is in the listen state
+ //
+ if ( SOCKET_STATE_LISTENING != pSocket->State ) {
+ DEBUG (( DEBUG_ACCEPT,
+ "ERROR - Socket is not listening!\r\n" ));
+ if ( NULL == pSocket->pApi->pfnAccept ) {
//
- // Update the socket state
+ // Socket does not support listen
//
- pSocket->State = SOCKET_STATE_NO_PORTS;
+ pSocket->errno = EOPNOTSUPP;
+ Status = EFI_UNSUPPORTED;
}
else {
//
- // Ports are available
- // No connection requests at this time
+ // Socket supports listen, but not in listen state
//
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
+ pSocket->errno = EINVAL;
+ Status = EFI_NOT_STARTED;
}
}
else {
-
//
- // Get the remote network address
+ // Determine if a socket is available
//
- pNewSocket = pSocket->pFifoHead;
- ASSERT ( NULL != pNewSocket );
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( 0 == pSocket->FifoDepth ) {
//
- // Determine the connection point within the network stack
+ // No connections available
+ // Determine if any ports are available
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_ACCEPT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpAccept4 ( pNewSocket,
- pSockAddr,
- pSockAddrLength );
- break;
-
- /*
- case SOCK_DGRAM:
- Status = UdpAccept4 ( pSocket );
- break;
- */
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // No ports available
+ //
+ Status = EFI_DEVICE_ERROR;
+ pSocket->errno = EINVAL;
+
+ //
+ // Update the socket state
+ //
+ pSocket->State = SOCKET_STATE_NO_PORTS;
}
- break;
- }
- if ( !EFI_ERROR ( Status )) {
- //
- // Remove the new socket from the list
- //
- pSocket->pFifoHead = pNewSocket->pNextConnection;
- if ( NULL == pSocket->pFifoHead ) {
- pSocket->pFifoTail = NULL;
+ else {
+ //
+ // Ports are available
+ // No connection requests at this time
+ //
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
}
+ }
+ else {
//
- // Account for this socket
+ // Attempt to accept the connection and
+ // get the remote network address
//
- pSocket->FifoDepth -= 1;
+ pNewSocket = pSocket->pFifoHead;
+ ASSERT ( NULL != pNewSocket );
+ Status = pSocket->pApi->pfnAccept ( pNewSocket,
+ pSockAddr,
+ pSockAddrLength );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Remove the new socket from the list
+ //
+ pSocket->pFifoHead = pNewSocket->pNextConnection;
+ if ( NULL == pSocket->pFifoHead ) {
+ pSocket->pFifoTail = NULL;
+ }
- //
- // Update the new socket's state
- //
- pNewSocket->State = SOCKET_STATE_CONNECTED;
- pNewSocket->bConfigured = TRUE;
- DEBUG (( DEBUG_ACCEPT,
- "0x%08x: Socket connected\r\n",
- pNewSocket ));
+ //
+ // Account for this socket
+ //
+ pSocket->FifoDepth -= 1;
+
+ //
+ // Update the new socket's state
+ //
+ pNewSocket->State = SOCKET_STATE_CONNECTED;
+ pNewSocket->bConfigured = TRUE;
+ DEBUG (( DEBUG_ACCEPT,
+ "0x%08x: Socket connected\r\n",
+ pNewSocket ));
+ }
}
}
- }
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
}
}
@@ -410,10 +927,9 @@ EslSocketAccept (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -422,9 +938,9 @@ EslSocketAccept (
/**
- Allocate and initialize a DT_SOCKET structure.
+ Allocate and initialize a ESL_SOCKET structure.
- The ::SocketAllocate() function allocates a DT_SOCKET structure
+ This support function allocates an ::ESL_SOCKET structure
and installs a protocol on ChildHandle. If pChildHandle is a
pointer to NULL, then a new handle is created and returned in
pChildHandle. If pChildHandle is not a pointer to NULL, then
@@ -436,11 +952,11 @@ EslSocketAccept (
then the protocol is added to the existing UEFI
handle.
@param [in] DebugFlags Flags for debug messages
- @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.
+ @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
@retval EFI_SUCCESS The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child
@retval other The child handle was not created
@@ -450,12 +966,12 @@ EFIAPI
EslSocketAllocate (
IN OUT EFI_HANDLE * pChildHandle,
IN UINTN DebugFlags,
- IN OUT DT_SOCKET ** ppSocket
+ IN OUT ESL_SOCKET ** ppSocket
)
{
UINTN LengthInBytes;
- DT_LAYER * pLayer;
- DT_SOCKET * pSocket;
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -465,12 +981,8 @@ EslSocketAllocate (
// Create a socket structure
//
LengthInBytes = sizeof ( *pSocket );
- Status = gBS->AllocatePool (
- EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **) &pSocket
- );
- if ( !EFI_ERROR ( Status )) {
+ pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );
+ if ( NULL != pSocket ) {
DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
"0x%08x: Allocate pSocket, %d bytes\r\n",
pSocket,
@@ -479,8 +991,6 @@ EslSocketAllocate (
//
// Initialize the socket protocol
//
- ZeroMem ( pSocket, LengthInBytes );
-
pSocket->Signature = SOCKET_SIGNATURE;
pSocket->SocketProtocol.pfnAccept = EslSocketAccept;
pSocket->SocketProtocol.pfnBind = EslSocketBind;
@@ -494,9 +1004,9 @@ EslSocketAllocate (
pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;
pSocket->SocketProtocol.pfnPoll = EslSocketPoll;
pSocket->SocketProtocol.pfnReceive = EslSocketReceive;
- pSocket->SocketProtocol.pfnSend = EslSocketTransmit;
pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;
pSocket->SocketProtocol.pfnSocket = EslSocket;
+ pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;
pSocket->MaxRxBuf = MAX_RX_DATA;
pSocket->MaxTxBuf = MAX_TX_DATA;
@@ -558,9 +1068,7 @@ EslSocketAllocate (
}
}
else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed socket allocation, Status: %r\r\n",
- Status ));
+ Status = EFI_OUT_OF_RESOURCES;
}
//
@@ -574,11 +1082,13 @@ EslSocketAllocate (
/**
Bind a name to a socket.
- The ::SocketBind routine connects a name to a socket on the local machine. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls the network specific layer to save the network
+ address of the local connection point.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::bind routine calls this routine to connect a name
+ (network address and port) to a socket on the local machine.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a sockaddr structure that contains the
connection point on the local machine. An IPv4 address
@@ -590,7 +1100,7 @@ EslSocketAllocate (
number from the dynamic range. Specifying a specific
port number causes the network layer to use that port.
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+ @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -600,12 +1110,18 @@ EslSocketAllocate (
EFI_STATUS
EslSocketBind (
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
- IN const struct sockaddr * pSockAddr,
+ IN CONST struct sockaddr * pSockAddr,
IN socklen_t SockAddrLength,
OUT int * pErrno
)
{
- DT_SOCKET * pSocket;
+ EFI_HANDLE ChildHandle;
+ UINT8 * pBuffer;
+ ESL_PORT * pPort;
+ ESL_SERVICE ** ppServiceListHead;
+ ESL_SOCKET * pSocket;
+ ESL_SERVICE * pService;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -626,91 +1142,130 @@ EslSocketBind (
//
// Validate the structure pointer
//
+ pSocket->errno = 0;
if ( NULL == pSockAddr ) {
DEBUG (( DEBUG_BIND,
"ERROR - pSockAddr is NULL!\r\n" ));
Status = EFI_INVALID_PARAMETER;
pSocket->errno = EFAULT;
}
- else{
+
+ //
+ // Validate the local address length
+ //
+ else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - Invalid bind name length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+
+ //
+ // Validate the shutdown state
+ //
+ else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - Shutdown has been called on socket 0x%08x\r\n",
+ pSocket ));
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Verify the socket state
+ //
+ else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - The socket 0x%08x is already configured!\r\n",
+ pSocket ));
+ pSocket->errno = EINVAL;
+ Status = EFI_ALREADY_STARTED;
+ }
+ else {
//
- // Validate the name length
+ // Synchronize with the socket layer
//
- if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))
- || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",
- SockAddrLength,
- pSockAddr->sa_len ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- else {
- //
- // Set the socket address length
- //
- if ( SockAddrLength > pSockAddr->sa_len ) {
- SockAddrLength = pSockAddr->sa_len;
- }
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ //
+ // Assume no ports are available
+ //
+ pSocket->errno = EADDRNOTAVAIL;
+ Status = EFI_INVALID_PARAMETER;
+ //
+ // Walk the list of services
+ //
+ pBuffer = (UINT8 *)&mEslLayer;
+ pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;
+ pService = *ppServiceListHead;
+ while ( NULL != pService ) {
//
- // Validate the local address
+ // Create the port
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
+ pServiceBinding = pService->pServiceBinding;
+ ChildHandle = NULL;
+ Status = pServiceBinding->CreateChild ( pServiceBinding,
+ &ChildHandle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: %s port handle created\r\n",
+ ChildHandle,
+ pService->pSocketBinding->pName ));
- case AF_INET:
//
- // Determine the connection point within the network stack
+ // Open the port
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpBind4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
-
- case SOCK_DGRAM:
- Status = EslUdpBind4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
- }
- break;
+ Status = EslSocketPortAllocate ( pSocket,
+ pService,
+ ChildHandle,
+ pSockAddr,
+ TRUE,
+ DEBUG_BIND,
+ &pPort );
+ }
+ else {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to open %s port handle, Status: %r\r\n",
+ pService->pSocketBinding->pName,
+ Status ));
}
//
- // Mark this socket as bound if successful
+ // Set the next service
//
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_BOUND;
+ pService = pService->pNext;
+ }
+
+ //
+ // Verify that at least one network connection was found
+ //
+ if ( NULL == pSocket->pPortList ) {
+ if ( EADDRNOTAVAIL == pSocket->errno ) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Socket address is not available!\r\n" ));
}
+ if ( EADDRINUSE == pSocket->errno ) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Socket address is in use!\r\n" ));
+ }
+ Status = EFI_INVALID_PARAMETER;
+ }
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ //
+ // Mark this socket as bound if successful
+ //
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_BOUND;
+ pSocket->errno = 0;
}
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
}
@@ -721,12 +1276,73 @@ EslSocketBind (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Test the bind configuration.
+
+ @param [in] pPort Address of the ::ESL_PORT structure.
+ @param [in] ErrnoValue errno value if test fails
+
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval Others The connection attempt failed.
+
+ **/
+EFI_STATUS
+EslSocketBindTest (
+ IN ESL_PORT * pPort,
+ IN int ErrnoValue
+ )
+{
+ UINT8 * pBuffer;
+ VOID * pConfigData;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the configuration data
+ //
+ pBuffer = (UINT8 *)pPort;
+ pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];
+ pConfigData = (VOID *)pBuffer;
+
+ //
+ // Attempt to use this configuration
+ //
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_WARN | DEBUG_BIND,
+ "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
+ pPort,
+ Status ));
+ pPort->pSocket->errno = ErrnoValue;
+ }
+ else {
+ //
+ // Reset the port
+ //
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND,
+ "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
+ pPort,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
}
}
+
+ //
+ // Return the operation status
+ //
DBG_EXIT_STATUS ( Status );
return Status;
}
@@ -735,9 +1351,14 @@ EslSocketBind (
/**
Determine if the socket is closed
- Reverses the operations of the ::SocketAllocate() routine.
+ This routine checks the state of the socket to determine if
+ the network specific layer has completed the close operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine polls this routine to determine when the
+ close operation is complete. The close operation needs to
+ reverse the operations of the ::EslSocketAllocate routine.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS Socket successfully closed
@@ -753,9 +1374,9 @@ EslSocketClosePoll (
)
{
int errno;
- DT_LAYER * pLayer;
- DT_SOCKET * pNextSocket;
- DT_SOCKET * pSocket;
+ ESL_LAYER * pLayer;
+ ESL_SOCKET * pNextSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -868,11 +1489,19 @@ EslSocketClosePoll (
/**
Start the close operation on the socket
- Start closing the socket by closing all of the ports. Upon
- completion, the ::SocketPoll() routine finishes closing the
- socket.
+ This routine calls the network specific layer to initiate the
+ close state machine. This routine then calls the network
+ specific layer to determine if the close state machine has gone
+ to completion. The result from this poll is returned to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine calls this routine to start the close
+ operation which reverses the operations of the
+ ::EslSocketAllocate routine. The close routine then polls
+ the ::EslSocketClosePoll routine to determine when the
+ socket is closed.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] bCloseNow Boolean to control close behavior
@param [out] pErrno Address to receive the errno value upon completion.
@@ -890,9 +1519,9 @@ EslSocketCloseStart (
)
{
int errno;
- DT_PORT * pNextPort;
- DT_PORT * pPort;
- DT_SOCKET * pSocket;
+ ESL_PORT * pNextPort;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -928,9 +1557,9 @@ EslSocketCloseStart (
// Start closing the ports
//
pNextPort = pPort->pLinkSocket;
- Status = pPort->pfnCloseStart ( pPort,
- bCloseNow,
- DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
+ Status = EslSocketPortCloseStart ( pPort,
+ bCloseNow,
+ DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
if (( EFI_SUCCESS != Status )
&& ( EFI_NOT_READY != Status )) {
errno = EIO;
@@ -951,8 +1580,8 @@ EslSocketCloseStart (
}
}
else {
- Status = EFI_ALREADY_STARTED;
- errno = EALREADY;
+ Status = EFI_NOT_READY;
+ errno = EAGAIN;
}
//
@@ -974,28 +1603,16 @@ EslSocketCloseStart (
/**
Connect to a remote system via the network.
- The ::SocketConnect routine attempts to establish a connection to a
- socket on the local or remote system using the specified address.
- The POSIX
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">connect</a>
- documentation is available online.
-
- There are three states associated with a connection:
- <ul>
- <li>Not connected</li>
- <li>Connection in progress</li>
- <li>Connected</li>
- </ul>
- In the "Not connected" state, calls to ::connect start the connection
- processing and update the state to "Connection in progress". During
- the "Connection in progress" state, connect polls for connection completion
- and moves the state to "Connected" after the connection is established.
- Note that these states are only visible when the file descriptor is marked
- with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection
- completes and may be used by poll or select as an indicator to call
- connect again.
+ This routine calls the network specific layer to establish
+ the remote system address and establish the connection to
+ the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::connect routine calls this routine to establish a
+ connection with the specified remote system. This routine
+ is designed to be polled by the connect routine for completion
+ of the network connection.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Network address of the remote system.
@@ -1016,7 +1633,9 @@ EslSocketConnect (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ struct sockaddr_in6 LocalAddress;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1037,12 +1656,10 @@ EslSocketConnect (
//
// Validate the name length
//
- if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))
- || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {
+ if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {
DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",
- SockAddrLength,
- pSockAddr->sa_len ));
+ "ERROR - Invalid bind name length: %d\r\n",
+ SockAddrLength ));
Status = EFI_INVALID_PARAMETER;
pSocket->errno = EINVAL;
}
@@ -1053,13 +1670,6 @@ EslSocketConnect (
pSocket->errno = 0;
//
- // Set the socket address length
- //
- if ( SockAddrLength > pSockAddr->sa_len ) {
- SockAddrLength = pSockAddr->sa_len;
- }
-
- //
// Synchronize with the socket layer
//
RAISE_TPL ( TplPrevious, TPL_SOCKETS );
@@ -1079,112 +1689,111 @@ EslSocketConnect (
case SOCKET_STATE_NOT_CONFIGURED:
case SOCKET_STATE_BOUND:
//
- // Validate the local address
+ // Validate the address length
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {
//
- // Determine the connection point within the network stack
+ // Verify the API
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {
//
- // Start the connection processing
+ // Already connected
//
- Status = EslTcpConnectStart4 ( pSocket,
- pSockAddr,
- SockAddrLength );
-
+ pSocket->errno = ENOTSUP;
+ Status = EFI_UNSUPPORTED;
+ }
+ else {
//
- // Set the next state if connecting
+ // Determine if BIND was already called
//
- if ( EFI_NOT_READY == Status ) {
- pSocket->State = SOCKET_STATE_CONNECTING;
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // Allow any local port
+ //
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
+ LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;
+ LocalAddress.sin6_family = pSocket->pApi->AddressFamily;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin6_len,
+ &pSocket->errno );
}
- break;
+ if ( NULL != pSocket->pPortList ) {
+ //
+ // Walk the list of ports
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Set the remote address
+ //
+ Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,
+ pSockAddr,
+ SockAddrLength );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
- case SOCK_DGRAM:
- Status = EslUdpConnect4 ( pSocket,
- pSockAddr,
- SockAddrLength );
- break;
+ //
+ // Set the next port
+ //
+ pPort = pPort->pLinkSocket;
+ }
+
+ //
+ // Verify the API
+ //
+ if (( !EFI_ERROR ( Status ))
+ && ( NULL != pSocket->pApi->pfnConnectStart )) {
+ //
+ // Initiate the connection with the remote system
+ //
+ Status = pSocket->pApi->pfnConnectStart ( pSocket );
+
+ //
+ // Set the next state if connecting
+ //
+ if ( EFI_NOT_READY == Status ) {
+ pSocket->State = SOCKET_STATE_CONNECTING;
+ }
+ }
+ }
}
- break;
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid address length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
}
break;
case SOCKET_STATE_CONNECTING:
//
- // Validate the local address
+ // Poll for connection completion
//
- switch ( pSockAddr->sa_family ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid bind address family: %d\r\n",
- pSockAddr->sa_family ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( NULL == pSocket->pApi->pfnConnectPoll ) {
//
- // Determine the connection point within the network stack
+ // Already connected
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Determine if the connection processing is completed
- //
- Status = EslTcpConnectPoll4 ( pSocket );
+ pSocket->errno = EISCONN;
+ Status = EFI_ALREADY_STARTED;
+ }
+ else {
+ Status = pSocket->pApi->pfnConnectPoll ( pSocket );
- //
- // Set the next state if connected
- //
- if ( EFI_NOT_READY != Status ) {
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_CONNECTED;
- }
- else {
- pSocket->State = SOCKET_STATE_BOUND;
- }
+ //
+ // Set the next state if connected
+ //
+ if ( EFI_NOT_READY != Status ) {
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_CONNECTED;
+ }
+ else {
+ pSocket->State = SOCKET_STATE_BOUND;
}
- break;
-
- case SOCK_DGRAM:
- //
- // Already connected
- //
- pSocket->errno = EISCONN;
- Status = EFI_ALREADY_STARTED;
- break;
}
- break;
}
break;
@@ -1211,15 +1820,14 @@ EslSocketConnect (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
//
// Bad socket protocol
//
DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
"ERROR - pSocketProtocol invalid!\r\n" ));
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
@@ -1232,213 +1840,96 @@ EslSocketConnect (
/**
- Creates a child handle and installs a protocol.
-
- The CreateChild() function installs a protocol on ChildHandle.
- If pChildHandle is a pointer to NULL, then a new handle is created and returned in pChildHandle.
- If pChildHandle is not a pointer to NULL, then the protocol installs on the existing pChildHandle.
-
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
- then a new handle is created. If it is a pointer to an existing UEFI handle,
- then the protocol is added to the existing UEFI handle.
-
- @retval EFI_SUCCESS The protocol was added to ChildHandle.
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
- the child
- @retval other The child handle was not created
+ Copy a fragmented buffer into a destination buffer.
-**/
-EFI_STATUS
-EFIAPI
-EslSocketCreateChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN OUT EFI_HANDLE * pChildHandle
- )
-{
- DT_SOCKET * pSocket;
- EFI_STATUS Status;
+ This support routine copies a fragmented buffer to the caller specified buffer.
- DBG_ENTER ( );
+ This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
- //
- // Create a socket structure
- //
- Status = EslSocketAllocate ( pChildHandle,
- DEBUG_SOCKET,
- &pSocket );
+ @param [in] FragmentCount Number of fragments in the table
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
+ @param [in] BufferLength Length of the the buffer
-/**
- Destroys a child handle with a protocol installed on it.
-
- The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
- that was installed by CreateChild() from ChildHandle. If the removed protocol is the
- last protocol on ChildHandle, then ChildHandle is destroyed.
+ @param [in] pBuffer Address of a buffer to receive the data.
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] ChildHandle Handle of the child to destroy
+ @param [in] pDataLength Number of received data bytes in the buffer.
- @retval EFI_SUCCESS The protocol was removed from ChildHandle.
- @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
- @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
- @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
- because its services are being used.
- @retval other The child handle was not destroyed
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EFIAPI
-EslSocketDestroyChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN EFI_HANDLE ChildHandle
+UINT8 *
+EslSocketCopyFragmentedBuffer (
+ IN UINT32 FragmentCount,
+ IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength
)
{
- DT_LAYER * pLayer;
- DT_SOCKET * pSocket;
- DT_SOCKET * pSocketPrevious;
- EFI_SOCKET_PROTOCOL * pSocketProtocol;
- EFI_STATUS Status;
- EFI_TPL TplPrevious;
+ size_t BytesToCopy;
+ UINT32 Fragment;
+ UINT8 * pBufferEnd;
+ UINT8 * pData;
DBG_ENTER ( );
//
- // Locate the socket control structure
+ // Validate the IP and UDP structures are identical
//
- pLayer = &mEslLayer;
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiSocketProtocolGuid,
- (VOID **)&pSocketProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if ( !EFI_ERROR ( Status )) {
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
-
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
+ //
+ // Copy the received data
+ //
+ Fragment = 0;
+ pBufferEnd = &pBuffer [ BufferLength ];
+ while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
//
- // Walk the socket list
+ // Determine the amount of received data
//
- pSocketPrevious = pLayer->pSocketList;
- if ( NULL != pSocketPrevious ) {
- if ( pSocket == pSocketPrevious ) {
- //
- // Remove the socket from the head of the list
- //
- pLayer->pSocketList = pSocket->pNext;
- }
- else {
- //
- // Find the socket in the middle of the list
- //
- while (( NULL != pSocketPrevious )
- && ( pSocket != pSocketPrevious->pNext )) {
- //
- // Set the next socket
- //
- pSocketPrevious = pSocketPrevious->pNext;
- }
- if ( NULL != pSocketPrevious ) {
- //
- // Remove the socket from the middle of the list
- //
- pSocketPrevious = pSocket->pNext;
- }
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Socket list is empty!\r\n" ));
+ pData = pFragmentTable[Fragment].FragmentBuffer;
+ BytesToCopy = pFragmentTable[Fragment].FragmentLength;
+ if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
+ BytesToCopy = pBufferEnd - pBuffer;
}
//
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
-
+ // Move the data into the buffer
//
- // Determine if the socket was found
- //
- if ( NULL != pSocketPrevious ) {
- pSocket->pNext = NULL;
-
- //
- // Remove the socket protocol
- //
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandle,
- &gEfiSocketProtocolGuid,
- &pSocket->SocketProtocol,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL | DEBUG_INFO,
- "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
- ChildHandle ));
-
- //
- // Free the socket structure
- //
- Status = gBS->FreePool ( pSocket );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Free pSocket, %d bytes\r\n",
- pSocket,
- sizeof ( *pSocket )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
- pSocket,
- Status ));
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
- "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
- ChildHandle,
- Status ));
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_INFO,
- "ERROR - The socket was not in the socket list!\r\n" ));
- Status = EFI_NOT_FOUND;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR,
- "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",
- ChildHandle,
- Status ));
+ DEBUG (( DEBUG_RX,
+ "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
+ pData,
+ pBuffer,
+ BytesToCopy ));
+ CopyMem ( pBuffer, pData, BytesToCopy );
+ pBuffer += BytesToCopy;
+ Fragment += 1;
}
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
Get the local address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the network
+ address of the local host connection point.
+
+ The ::getsockname routine calls this routine to obtain the network
+ address associated with the local host connection point.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pAddress Network address to receive the local system address
@@ -1457,7 +1948,9 @@ EslSocketGetLocalAddress (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ socklen_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1476,78 +1969,78 @@ EslSocketGetLocalAddress (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Verify the address buffer and length address
+ // Verify the socket state
//
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Verify the socket state
+ // Verify the address buffer and length address
//
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
- //
- // Synchronize with the socket layer
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ // Verify the socket state
//
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
//
- // Determine the connection point within the network stack
+ // Verify the API
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Get the local address
+ // Synchronize with the socket layer
//
- Status = EslTcpGetLocalAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_DGRAM:
//
- // Get the local address
+ // Verify that there is just a single connection
//
- Status = EslUdpGetLocalAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = pSocket->pApi->AddressLength;
+ if (( LengthInBytes <= *pAddressLength )
+ && ( 255 >= LengthInBytes )) {
+ //
+ // Return the local address and address length
+ //
+ ZeroMem ( pAddress, LengthInBytes );
+ pAddress->sa_len = (uint8_t)LengthInBytes;
+ *pAddressLength = pAddress->sa_len;
+ pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
- break;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
}
else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
}
}
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
}
//
@@ -1557,10 +2050,9 @@ EslSocketGetLocalAddress (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -1571,7 +2063,13 @@ EslSocketGetLocalAddress (
/**
Get the peer address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the remote
+ system connection point.
+
+ The ::getpeername routine calls this routine to obtain the network
+ address of the remote connection point.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pAddress Network address to receive the remote system address
@@ -1590,7 +2088,9 @@ EslSocketGetPeerAddress (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ socklen_t LengthInBytes;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -1609,80 +2109,79 @@ EslSocketGetPeerAddress (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Verify the address buffer and length address
+ // Verify the socket state
//
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Verify the socket state
+ // Verify the API
//
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Validate the local address
+ // Verify the address buffer and length address
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
//
- // Determine the connection point within the network stack
+ // Verify the socket state
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
//
- // Verify the port state
+ // Verify that there is just a single connection
//
- Status = EslTcpGetRemoteAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = pSocket->pApi->AddressLength;
+ if ( LengthInBytes <= *pAddressLength ) {
+ //
+ // Return the local address
+ //
+ ZeroMem ( pAddress, LengthInBytes );
+ pAddress->sa_len = (uint8_t)LengthInBytes;
+ *pAddressLength = pAddress->sa_len;
+ pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
- case SOCK_DGRAM:
//
- // Verify the port state
+ // Release the socket layer synchronization
//
- Status = EslUdpGetRemoteAddress4 ( pSocket,
- pAddress,
- pAddressLength );
- break;
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
}
- break;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
}
}
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
}
-
+
//
// Return the operation status
//
@@ -1690,28 +2189,296 @@ EslSocketGetPeerAddress (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Free the ESL_IO_MGMT event and structure
+
+ This support routine walks the free list to close the event in
+ the ESL_IO_MGMT structure and remove the structure from the free
+ list.
+
+ See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
+EFI_STATUS
+EslSocketIoFree (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName
+ )
+{
+ UINT8 * pBuffer;
+ EFI_EVENT * pEvent;
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Walk the list of IO structures
+ //
+ pSocket = pPort->pSocket;
+ while ( *ppFreeQueue ) {
+ //
+ // Free the event for this structure
+ //
+ pIo = *ppFreeQueue;
+ pBuffer = (UINT8 *)pIo;
+ pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
+ pEvent = (EFI_EVENT *)pBuffer;
+ Status = gBS->CloseEvent ( *pEvent );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the %a event, Status: %r\r\n",
+ pEventName,
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DebugFlags,
+ "0x%08x: Closed %a event 0x%08x\r\n",
+ pIo,
+ pEventName,
+ *pEvent ));
+
+ //
+ // Remove this structure from the queue
+ //
+ *ppFreeQueue = pIo->pNext;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Initialize the ESL_IO_MGMT structures
+
+ This support routine initializes the ESL_IO_MGMT structure and
+ places them on to a free list.
+
+ This routine is called by ::EslSocketPortAllocate routines to prepare
+ the transmit engines. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in, out] ppIo Address containing the first structure address. Upon
+ return this buffer contains the next structure address.
+ @param [in] TokenCount Number of structures to initialize
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+ @param [in] pfnCompletion Completion routine address
+
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
+EFI_STATUS
+EslSocketIoInit (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppIo,
+ IN UINTN TokenCount,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName,
+ IN EFI_EVENT_NOTIFY pfnCompletion
+ )
+{
+ ESL_IO_MGMT * pEnd;
+ EFI_EVENT * pEvent;
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Walk the list of IO structures
+ //
+ pSocket = pPort->pSocket;
+ pIo = *ppIo;
+ pEnd = &pIo [ TokenCount ];
+ while ( pEnd > pIo ) {
+ //
+ // Initialize the IO structure
+ //
+ pIo->pPort = pPort;
+ pIo->pPacket = NULL;
+
+ //
+ // Allocate the event for this structure
+ //
+ pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)pfnCompletion,
+ pIo,
+ pEvent );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the %a event, Status: %r\r\n",
+ pEventName,
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
}
+ DEBUG (( DebugFlags,
+ "0x%08x: Created %a event 0x%08x\r\n",
+ pIo,
+ pEventName,
+ *pEvent ));
+
+ //
+ // Add this structure to the queue
+ //
+ pIo->pNext = *ppFreeQueue;
+ *ppFreeQueue = pIo;
+
+ //
+ // Set the next structure
+ //
+ pIo += 1;
}
+
+ //
+ // Save the next structure
+ //
+ *ppIo = pIo;
+
+ //
+ // Return the operation status
+ //
DBG_EXIT_STATUS ( Status );
return Status;
}
/**
+ Determine if the socket is configured
+
+ This support routine is called to determine if the socket if the
+ configuration call was made to the network layer. The following
+ routines call this routine to verify that they may be successful
+ in their operations:
+ <ul>
+ <li>::EslSocketGetLocalAddress</li>
+ <li>::EslSocketGetPeerAddress</li>
+ <li>::EslSocketPoll</li>
+ <li>::EslSocketReceive</li>
+ <li>::EslSocketTransmit</li>
+ </ul>
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The socket is configured
+
+**/
+EFI_STATUS
+EslSocketIsConfigured (
+ IN ESL_SOCKET * pSocket
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Verify the socket state
+ //
+ if ( !pSocket->bConfigured ) {
+ DBG_ENTER ( );
+
+ //
+ // Verify the API
+ //
+ if ( NULL == pSocket->pApi->pfnIsConfigured ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+
+ //
+ // Determine if the socket is configured
+ //
+ Status = pSocket->pApi->pfnIsConfigured ( pSocket );
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ //
+ // Set errno if a failure occurs
+ //
+ if ( EFI_ERROR ( Status )) {
+ pSocket->errno = EADDRNOTAVAIL;
+ }
+ }
+
+ DBG_EXIT_STATUS ( Status );
+ }
+
+ //
+ // Return the configuration status
+ //
+ return Status;
+}
+
+
+/**
Establish the known port to listen for network connections.
- The ::SocketListen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::SocketAccept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
+ This routine calls into the network protocol layer to establish
+ a handler that is called upon connection completion. The handler
+ is responsible for inserting the connection into the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::listen routine indirectly calls this routine to place the
+ socket into a state that enables connection attempts. Connections
+ are placed in a FIFO that is serviced by the application. The
+ application calls the ::accept (::EslSocketAccept) routine to
+ remove the next connection from the FIFO and get the associated
+ socket and address.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Backlog Backlog specifies the maximum FIFO depth for
the connections waiting for the application
@@ -1731,7 +2498,7 @@ EslSocketListen (
OUT int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_STATUS TempStatus;
EFI_TPL TplPrevious;
@@ -1751,127 +2518,105 @@ EslSocketListen (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Assume success
- //
- pSocket->Status = EFI_SUCCESS;
- pSocket->errno = 0;
-
+ // Verify the API
//
- // Verify that the bind operation was successful
- //
- if ( SOCKET_STATE_BOUND == pSocket->State ) {
+ if ( NULL == pSocket->pApi->pfnListen ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Synchronize with the socket layer
+ // Assume success
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
+ pSocket->Status = EFI_SUCCESS;
+ pSocket->errno = 0;
//
- // Create the event for SocketAccept completion
+ // Verify that the bind operation was successful
//
- Status = gBS->CreateEvent ( 0,
- TplPrevious,
- NULL,
- NULL,
- &pSocket->WaitAccept );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Created WaitAccept event\r\n",
- pSocket->WaitAccept ));
+ if ( SOCKET_STATE_BOUND == pSocket->State ) {
//
- // Set the maximum FIFO depth
+ // Synchronize with the socket layer
//
- if ( 0 >= Backlog ) {
- Backlog = MAX_PENDING_CONNECTIONS;
- }
- else {
- if ( SOMAXCONN < Backlog ) {
- Backlog = SOMAXCONN;
- }
- else {
- pSocket->MaxFifoDepth = Backlog;
- }
- }
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
//
- // Validate the local address
+ // Create the event for SocketAccept completion
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ Status = gBS->CreateEvent ( 0,
+ TplPrevious,
+ NULL,
+ NULL,
+ &pSocket->WaitAccept );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Created WaitAccept event\r\n",
+ pSocket->WaitAccept ));
//
- // Determine the connection point within the network stack
+ // Set the maximum FIFO depth
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpListen4 ( pSocket );
- break;
-
-/*
- case SOCK_DGRAM:
- Status = UdpListen4 ( pSocket );
- break;
-*/
+ if ( 0 >= Backlog ) {
+ Backlog = MAX_PENDING_CONNECTIONS;
+ }
+ else {
+ if ( SOMAXCONN < Backlog ) {
+ Backlog = SOMAXCONN;
+ }
+ else {
+ pSocket->MaxFifoDepth = Backlog;
+ }
}
- break;
- }
- //
- // Place the socket in the listen state if successful
- //
- if ( !EFI_ERROR ( Status )) {
- pSocket->State = SOCKET_STATE_LISTENING;
- }
- else {
//
- // Not waiting for SocketAccept to complete
+ // Initiate the connection attempt listen
+ //
+ Status = pSocket->pApi->pfnListen ( pSocket );
+
+ //
+ // Place the socket in the listen state if successful
//
- TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_POOL,
- "0x%08x: Closed WaitAccept event\r\n",
- pSocket->WaitAccept ));
- pSocket->WaitAccept = NULL;
+ if ( !EFI_ERROR ( Status )) {
+ pSocket->State = SOCKET_STATE_LISTENING;
+ pSocket->bListenCalled = TRUE;
}
else {
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,
- "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
+ //
+ // Not waiting for SocketAccept to complete
+ //
+ TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
+ if ( !EFI_ERROR ( TempStatus )) {
+ DEBUG (( DEBUG_POOL,
+ "0x%08x: Closed WaitAccept event\r\n",
+ pSocket->WaitAccept ));
+ pSocket->WaitAccept = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,
+ "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
+ TempStatus ));
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
}
}
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
+ "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
- "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
+ "ERROR - Bind operation must be performed first!\r\n" ));
+ pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
+ : EINVAL;
+ Status = EFI_NO_MAPPING;
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
- "ERROR - Bind operation must be performed first!\r\n" ));
- pSocket->errno = EDESTADDRREQ;
}
}
@@ -1882,10 +2627,9 @@ EslSocketListen (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -1896,11 +2640,13 @@ EslSocketListen (
/**
Get the socket options
- Retrieve the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::getsockopt routine calls this routine to retrieve the
+ socket options one at a time by name.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [out] pOptionValue Buffer to receive the option value
@@ -1925,7 +2671,7 @@ EslSocketOptionGet (
socklen_t LengthInBytes;
socklen_t MaxBytes;
UINT8 * pOptionData;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -1940,9 +2686,16 @@ EslSocketOptionGet (
// Validate the socket
//
pSocket = NULL;
- if (( NULL != pSocketProtocol )
- && ( NULL != pOptionValue )
- && ( NULL != pOptionLength )) {
+ if ( NULL == pSocketProtocol ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
+ }
+ else if ( NULL == pOptionValue ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
+ }
+ else if ( NULL == pOptionLength ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
+ }
+ else {
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
LengthInBytes = 0;
MaxBytes = *pOptionLength;
@@ -1950,20 +2703,70 @@ EslSocketOptionGet (
switch ( level ) {
default:
//
- // Protocol level not supported
+ // See if the protocol will handle the option
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
+ if ( NULL != pSocket->pApi->pfnOptionGet ) {
+ if ( pSocket->pApi->DefaultProtocol == level ) {
+ Status = pSocket->pApi->pfnOptionGet ( pSocket,
+ OptionName,
+ &pOptionData,
+ &LengthInBytes );
+ errno = pSocket->errno;
+ break;
+ }
+ else {
+ //
+ // Protocol not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - The socket does not support this protocol!\r\n" ));
+ }
+ }
+ else {
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - %a does not support any options!\r\n",
+ pSocket->pApi->pName ));
+ }
+ errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
break;
case SOL_SOCKET:
switch ( OptionName ) {
default:
//
- // Option not supported
+ // Socket option not supported
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
+ DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
+ errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case SO_ACCEPTCONN:
+ //
+ // Return the listen flag
+ //
+ pOptionData = (UINT8 *)&pSocket->bListenCalled;
+ LengthInBytes = sizeof ( pSocket->bListenCalled );
+ break;
+
+ case SO_DEBUG:
+ //
+ // Return the debug flags
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+ break;
+
+ case SO_OOBINLINE:
+ //
+ // Return the out-of-band inline flag
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
break;
case SO_RCVTIMEO:
@@ -1976,7 +2779,7 @@ EslSocketOptionGet (
case SO_RCVBUF:
//
- // Return the maximum transmit buffer size
+ // Return the maximum receive buffer size
//
pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
LengthInBytes = sizeof ( pSocket->MaxRxBuf );
@@ -2007,16 +2810,31 @@ EslSocketOptionGet (
*pOptionLength = LengthInBytes;
//
- // Return the option value
+ // Determine if the option is present
//
- if ( NULL != pOptionData ) {
+ if ( 0 != LengthInBytes ) {
//
// Silently truncate the value length
//
if ( LengthInBytes > MaxBytes ) {
+ DEBUG (( DEBUG_OPTION,
+ "INFO - Truncating option from %d to %d bytes\r\n",
+ LengthInBytes,
+ MaxBytes ));
LengthInBytes = MaxBytes;
}
+
+ //
+ // Return the value
+ //
CopyMem ( pOptionValue, pOptionData, LengthInBytes );
+
+ //
+ // Zero fill any remaining space
+ //
+ if ( LengthInBytes < MaxBytes ) {
+ ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
+ }
errno = 0;
Status = EFI_SUCCESS;
}
@@ -2036,18 +2854,20 @@ EslSocketOptionGet (
/**
Set the socket options
- Adjust the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::setsockopt routine calls this routine to adjust the socket
+ options one at a time by name.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [in] pOptionValue Buffer containing the option value
@param [in] OptionLength Length of the buffer in bytes
@param [out] pErrno Address to receive the errno value upon completion.
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Option successfully set
**/
EFI_STATUS
@@ -2060,10 +2880,11 @@ EslSocketOptionSet (
IN int * pErrno
)
{
+ BOOLEAN bTrueFalse;
int errno;
socklen_t LengthInBytes;
UINT8 * pOptionData;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2073,80 +2894,160 @@ EslSocketOptionSet (
//
errno = EINVAL;
Status = EFI_INVALID_PARAMETER;
-
+
//
// Validate the socket
//
pSocket = NULL;
- if (( NULL != pSocketProtocol )
- && ( NULL != pOptionValue )) {
+ if ( NULL == pSocketProtocol ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
+ }
+ else if ( NULL == pOptionValue ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
+ }
+ else
+ {
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
- LengthInBytes = 0;
- pOptionData = NULL;
- switch ( level ) {
- default:
- //
- // Protocol level not supported
- //
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
- break;
-
- case SOL_SOCKET:
- switch ( OptionName ) {
+ if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
+ DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
+ }
+ else {
+ LengthInBytes = 0;
+ pOptionData = NULL;
+ switch ( level ) {
default:
//
- // Option not supported
+ // See if the protocol will handle the option
//
- errno = ENOTSUP;
- Status = EFI_UNSUPPORTED;
- break;
-
- case SO_RCVTIMEO:
- //
- // Return the receive timeout
- //
- pOptionData = (UINT8 *)&pSocket->RxTimeout;
- LengthInBytes = sizeof ( pSocket->RxTimeout );
+ if ( NULL != pSocket->pApi->pfnOptionSet ) {
+ if ( pSocket->pApi->DefaultProtocol == level ) {
+ Status = pSocket->pApi->pfnOptionSet ( pSocket,
+ OptionName,
+ pOptionValue,
+ OptionLength );
+ errno = pSocket->errno;
+ break;
+ }
+ else {
+ //
+ // Protocol not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - The socket does not support this protocol!\r\n" ));
+ }
+ }
+ else {
+ //
+ // Protocol level not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - %a does not support any options!\r\n",
+ pSocket->pApi->pName ));
+ }
+ errno = ENOPROTOOPT;
+ Status = EFI_INVALID_PARAMETER;
break;
+
+ case SOL_SOCKET:
+ switch ( OptionName ) {
+ default:
+ //
+ // Option not supported
+ //
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - Sockets does not support this option!\r\n" ));
+ errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ break;
- case SO_RCVBUF:
- //
- // Return the maximum transmit buffer size
- //
- pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
- LengthInBytes = sizeof ( pSocket->MaxRxBuf );
- break;
+ case SO_DEBUG:
+ //
+ // Set the debug flags
+ //
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+ break;
- case SO_SNDBUF:
- //
- // Send buffer size
- //
- //
- // Return the maximum transmit buffer size
- //
- pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
- LengthInBytes = sizeof ( pSocket->MaxTxBuf );
+ case SO_OOBINLINE:
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;
+ LengthInBytes = sizeof ( pSocket->bOobInLine );
+
+ //
+ // Validate the option length
+ //
+ if ( sizeof ( UINT32 ) == OptionLength ) {
+ //
+ // Restrict the input to TRUE or FALSE
+ //
+ bTrueFalse = TRUE;
+ if ( 0 == *(UINT32 *)pOptionValue ) {
+ bTrueFalse = FALSE;
+ }
+ pOptionValue = &bTrueFalse;
+ }
+ else {
+ //
+ // Force an invalid option length error
+ //
+ OptionLength = LengthInBytes - 1;
+ }
+ break;
+
+ case SO_RCVTIMEO:
+ //
+ // Return the receive timeout
+ //
+ pOptionData = (UINT8 *)&pSocket->RxTimeout;
+ LengthInBytes = sizeof ( pSocket->RxTimeout );
+ break;
+
+ case SO_RCVBUF:
+ //
+ // Return the maximum receive buffer size
+ //
+ pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );
+ break;
+
+ case SO_SNDBUF:
+ //
+ // Send buffer size
+ //
+ //
+ // Return the maximum transmit buffer size
+ //
+ pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
+ LengthInBytes = sizeof ( pSocket->MaxTxBuf );
+ break;
+ }
break;
}
- break;
- }
- //
- // Validate the option length
- //
- if ( LengthInBytes <= OptionLength ) {
//
- // Set the option value
+ // Determine if an option was found
//
- if ( NULL != pOptionData ) {
- CopyMem ( pOptionData, pOptionValue, LengthInBytes );
- errno = 0;
- Status = EFI_SUCCESS;
+ if ( 0 != LengthInBytes ) {
+ //
+ // Validate the option length
+ //
+ if ( LengthInBytes <= OptionLength ) {
+ //
+ // Set the option value
+ //
+ CopyMem ( pOptionData, pOptionValue, LengthInBytes );
+ errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ DEBUG (( DEBUG_OPTION,
+ "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
+ OptionLength,
+ LengthInBytes ));
+ }
}
}
}
-
+
//
// Return the operation status
//
@@ -2161,8 +3062,13 @@ EslSocketOptionSet (
/**
Allocate a packet for a receive or transmit operation
- @param [in] ppPacket Address to receive the DT_PACKET structure
+ This support routine is called by ::EslSocketRxStart and the
+ network specific TxBuffer routines to get buffer space for the
+ next operation.
+
+ @param [in] ppPacket Address to receive the ::ESL_PACKET structure
@param [in] LengthInBytes Length of the packet structure
+ @param [in] ZeroBytes Length of packet to zero
@param [in] DebugFlags Flags for debug messages
@retval EFI_SUCCESS - The packet was allocated successfully
@@ -2170,12 +3076,13 @@ EslSocketOptionSet (
**/
EFI_STATUS
EslSocketPacketAllocate (
- IN DT_PACKET ** ppPacket,
+ IN ESL_PACKET ** ppPacket,
IN size_t LengthInBytes,
+ IN size_t ZeroBytes,
IN UINTN DebugFlags
)
{
- DT_PACKET * pPacket;
+ ESL_PACKET * pPacket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2193,6 +3100,9 @@ EslSocketPacketAllocate (
"0x%08x: Allocate pPacket, %d bytes\r\n",
pPacket,
LengthInBytes ));
+ if ( 0 != ZeroBytes ) {
+ ZeroMem ( &pPacket->Op, ZeroBytes );
+ }
pPacket->PacketSize = LengthInBytes;
}
else {
@@ -2219,7 +3129,12 @@ EslSocketPacketAllocate (
/**
Free a packet used for receive or transmit operation
- @param [in] pPacket Address of the DT_PACKET structure
+ This support routine is called by the network specific Close
+ and TxComplete routines and during error cases in RxComplete
+ and TxBuffer. Note that the network layers typically place
+ receive packets on the ESL_SOCKET::pRxFree list for reuse.
+
+ @param [in] pPacket Address of an ::ESL_PACKET structure
@param [in] DebugFlags Flags for debug messages
@retval EFI_SUCCESS - The packet was allocated successfully
@@ -2227,7 +3142,7 @@ EslSocketPacketAllocate (
**/
EFI_STATUS
EslSocketPacketFree (
- IN DT_PACKET * pPacket,
+ IN ESL_PACKET * pPacket,
IN UINTN DebugFlags
)
{
@@ -2265,10 +3180,14 @@ EslSocketPacketFree (
/**
Poll a socket for pending activity.
- The SocketPoll routine checks a socket for pending activity associated
- with the event mask. Activity is returned in the detected event buffer.
+ This routine builds a detected event mask which is returned to
+ the caller in the buffer provided.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::poll routine calls this routine to determine if the socket
+ needs to be serviced as a result of connection, error, receive or
+ transmit activity.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Events Events of interest for this socket
@@ -2289,9 +3208,8 @@ EslSocketPoll (
)
{
short DetectedEvents;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
- EFI_TPL TplPrevious;
short ValidEvents;
DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
@@ -2307,60 +3225,7 @@ EslSocketPoll (
//
// Verify the socket state
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
- //
- // Determine the connection point within the network stack
- //
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Verify the port state
- //
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
- break;
- }
- break;
- }
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
- }
+ Status = EslSocketIsConfigured ( pSocket );
if ( !EFI_ERROR ( Status )) {
//
// Check for invalid events
@@ -2472,10 +3337,902 @@ EslSocketPoll (
/**
+ Allocate and initialize a ESL_PORT structure.
+
+ This routine initializes an ::ESL_PORT structure for use by
+ the socket. This routine calls a routine via
+ ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
+ specific resources. The resources are released later by the
+ \ref PortCloseStateMachine.
+
+ This support routine is called by:
+ <ul>
+ <li>::EslSocketBind</li>
+ <li>::EslTcp4ListenComplete</li>
+ </ul>
+ to connect the socket with the underlying network adapter
+ to the socket.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+ @param [in] pService Address of an ::ESL_SERVICE structure.
+ @param [in] ChildHandle Network protocol child handle
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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 if EslSocketBindTest should be called
+ @param [in] DebugFlags Flags for debug messages
+ @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslSocketPortAllocate (
+ IN ESL_SOCKET * pSocket,
+ IN ESL_SERVICE * pService,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest,
+ IN UINTN DebugFlags,
+ OUT ESL_PORT ** ppPort
+ )
+{
+ UINTN LengthInBytes;
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_LAYER * pLayer;
+ ESL_PORT * pPort;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ EFI_STATUS Status;
+ EFI_STATUS TempStatus;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Use for/break instead of goto
+ pSocketBinding = pService->pSocketBinding;
+ for ( ; ; ) {
+ //
+ // Allocate a port structure
+ //
+ pLayer = &mEslLayer;
+ LengthInBytes = sizeof ( *pPort )
+ + ESL_STRUCTURE_ALIGNMENT_BYTES
+ + (( pSocketBinding->RxIo
+ + pSocketBinding->TxIoNormal
+ + pSocketBinding->TxIoUrgent )
+ * sizeof ( ESL_IO_MGMT ));
+ pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
+ if ( NULL == pPort ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
+ "0x%08x: Allocate pPort, %d bytes\r\n",
+ pPort,
+ LengthInBytes ));
+
+ //
+ // Initialize the port
+ //
+ pPort->DebugFlags = DebugFlags;
+ pPort->Handle = ChildHandle;
+ pPort->pService = pService;
+ pPort->pServiceBinding = pService->pServiceBinding;
+ pPort->pSocket = pSocket;
+ pPort->pSocketBinding = pService->pSocketBinding;
+ pPort->Signature = PORT_SIGNATURE;
+
+ //
+ // Open the port protocol
+ //
+ Status = gBS->OpenProtocol ( pPort->Handle,
+ pSocketBinding->pNetworkProtocolGuid,
+ &pPort->pProtocol.v,
+ pLayer->ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
+ pPort->Handle ));
+ pSocket->errno = EEXIST;
+ break;
+ }
+ DEBUG (( DebugFlags,
+ "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
+ pPort->pProtocol.v,
+ pPort->Handle ));
+
+ //
+ // Initialize the port specific resources
+ //
+ Status = pSocket->pApi->pfnPortAllocate ( pPort,
+ DebugFlags );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Set the local address
+ //
+ Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Test the address/port configuration
+ //
+ if ( bBindTest ) {
+ Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the receive structures
+ //
+ pBuffer = (UINT8 *)&pPort[ 1 ];
+ pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
+ pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
+ pIo = (ESL_IO_MGMT *)pBuffer;
+ if (( 0 != pSocketBinding->RxIo )
+ && ( NULL != pSocket->pApi->pfnRxComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->RxIo,
+ &pPort->pRxFree,
+ DebugFlags | DEBUG_POOL,
+ "receive",
+ pSocket->pApi->pfnRxComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the urgent transmit structures
+ //
+ if (( 0 != pSocketBinding->TxIoUrgent )
+ && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->TxIoUrgent,
+ &pPort->pTxOobFree,
+ DebugFlags | DEBUG_POOL,
+ "urgent transmit",
+ pSocket->pApi->pfnTxOobComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Initialize the normal transmit structures
+ //
+ if (( 0 != pSocketBinding->TxIoNormal )
+ && ( NULL != pSocket->pApi->pfnTxComplete )) {
+ Status = EslSocketIoInit ( pPort,
+ &pIo,
+ pSocketBinding->TxIoNormal,
+ &pPort->pTxFree,
+ DebugFlags | DEBUG_POOL,
+ "normal transmit",
+ pSocket->pApi->pfnTxComplete );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+
+ //
+ // Add this port to the socket
+ //
+ pPort->pLinkSocket = pSocket->pPortList;
+ pSocket->pPortList = pPort;
+ DEBUG (( DebugFlags,
+ "0x%08x: Socket adding port: 0x%08x\r\n",
+ pSocket,
+ pPort ));
+
+ //
+ // Add this port to the service
+ //
+ pPort->pLinkService = pService->pPortList;
+ pService->pPortList = pPort;
+
+ //
+ // Return the port
+ //
+ *ppPort = pPort;
+ break;
+ }
+
+ //
+ // Clean up after the error if necessary
+ //
+ if ( EFI_ERROR ( Status )) {
+ if ( NULL != pPort ) {
+ //
+ // Close the port
+ //
+ EslSocketPortClose ( pPort );
+ }
+ else {
+ //
+ // Close the port if necessary
+ //
+ pServiceBinding = pService->pServiceBinding;
+ TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
+ ChildHandle );
+ if ( !EFI_ERROR ( TempStatus )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: %s port handle destroyed\r\n",
+ ChildHandle,
+ pSocketBinding->pName ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
+ pSocketBinding->pName,
+ ChildHandle,
+ TempStatus ));
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
+ }
+ }
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Close a port.
+
+ This routine releases the resources allocated by ::EslSocketPortAllocate.
+ This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
+ specific resources.
+
+ This routine is called by:
+ <ul>
+ <li>::EslSocketPortAllocate - Port initialization failure</li>
+ <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
+ <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
+ </ul>
+ 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
+EslSocketPortClose (
+ IN ESL_PORT * pPort
+ )
+{
+ UINTN DebugFlags;
+ ESL_LAYER * pLayer;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPreviousPort;
+ ESL_SERVICE * pService;
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the port in the socket list
+ //
+ Status = EFI_SUCCESS;
+ pLayer = &mEslLayer;
+ DebugFlags = pPort->DebugFlags;
+ pSocket = pPort->pSocket;
+ pPreviousPort = pSocket->pPortList;
+ if ( pPreviousPort == pPort ) {
+ //
+ // Remove this port from the head of the socket list
+ //
+ pSocket->pPortList = pPort->pLinkSocket;
+ }
+ else {
+ //
+ // Locate the port in the middle of the socket list
+ //
+ while (( NULL != pPreviousPort )
+ && ( pPreviousPort->pLinkSocket != pPort )) {
+ pPreviousPort = pPreviousPort->pLinkSocket;
+ }
+ if ( NULL != pPreviousPort ) {
+ //
+ // Remove the port from the middle of the socket list
+ //
+ pPreviousPort->pLinkSocket = pPort->pLinkSocket;
+ }
+ }
+
+ //
+ // Locate the port in the service list
+ // Note that the port may not be in the service list
+ // if the service has been shutdown.
+ //
+ pService = pPort->pService;
+ if ( NULL != pService ) {
+ pPreviousPort = pService->pPortList;
+ if ( pPreviousPort == pPort ) {
+ //
+ // Remove this port from the head of the service list
+ //
+ pService->pPortList = pPort->pLinkService;
+ }
+ else {
+ //
+ // Locate the port in the middle of the service list
+ //
+ while (( NULL != pPreviousPort )
+ && ( pPreviousPort->pLinkService != pPort )) {
+ pPreviousPort = pPreviousPort->pLinkService;
+ }
+ if ( NULL != pPreviousPort ) {
+ //
+ // Remove the port from the middle of the service list
+ //
+ pPreviousPort->pLinkService = pPort->pLinkService;
+ }
+ }
+ }
+
+ //
+ // Empty the urgent receive queue
+ //
+ while ( NULL != pSocket->pRxOobPacketListHead ) {
+ pPacket = pSocket->pRxOobPacketListHead;
+ pSocket->pRxOobPacketListHead = pPacket->pNext;
+ pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ pSocket->pRxOobPacketListTail = NULL;
+ ASSERT ( 0 == pSocket->RxOobBytes );
+
+ //
+ // Empty the receive queue
+ //
+ while ( NULL != pSocket->pRxPacketListHead ) {
+ pPacket = pSocket->pRxPacketListHead;
+ pSocket->pRxPacketListHead = pPacket->pNext;
+ pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ pSocket->pRxPacketListTail = NULL;
+ ASSERT ( 0 == pSocket->RxBytes );
+
+ //
+ // Empty the receive free queue
+ //
+ while ( NULL != pSocket->pRxFree ) {
+ pPacket = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+
+ //
+ // Release the network specific resources
+ //
+ if ( NULL != pSocket->pApi->pfnPortClose ) {
+ Status = pSocket->pApi->pfnPortClose ( pPort );
+ }
+
+ //
+ // Done with the normal transmit events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pTxFree,
+ DebugFlags | DEBUG_POOL,
+ "normal transmit" );
+
+ //
+ // Done with the urgent transmit events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pTxOobFree,
+ DebugFlags | DEBUG_POOL,
+ "urgent transmit" );
+
+ //
+ // Done with the receive events
+ //
+ Status = EslSocketIoFree ( pPort,
+ &pPort->pRxFree,
+ DebugFlags | DEBUG_POOL,
+ "receive" );
+
+ //
+ // Done with the lower layer network protocol
+ //
+ pSocketBinding = pPort->pSocketBinding;
+ if ( NULL != pPort->pProtocol.v ) {
+ Status = gBS->CloseProtocol ( pPort->Handle,
+ pSocketBinding->pNetworkProtocolGuid,
+ pLayer->ImageHandle,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags,
+ "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
+ pPort->pProtocol.v,
+ pPort->Handle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
+ pPort->Handle,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the network port
+ //
+ pServiceBinding = pPort->pServiceBinding;
+ if ( NULL != pPort->Handle ) {
+ Status = pServiceBinding->DestroyChild ( pServiceBinding,
+ pPort->Handle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: %s port handle destroyed\r\n",
+ pPort->Handle,
+ pSocketBinding->pName ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
+ "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
+ pSocketBinding->pName,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Release the port structure
+ //
+ Status = gBS->FreePool ( pPort );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Free pPort, %d bytes\r\n",
+ pPort,
+ sizeof ( *pPort )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
+ "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+
+ //
+ // Mark the socket as closed if necessary
+ //
+ if ( NULL == pSocket->pPortList ) {
+ pSocket->State = SOCKET_STATE_CLOSED;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
+ pSocket ));
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 3
+
+ This routine attempts to complete the port close operation.
+
+ This routine is called by the TCP layer upon completion of
+ the close operation and by ::EslSocketPortCloseTxDone.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] Event The close completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+**/
+VOID
+EslSocketPortCloseComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ )
+{
+ ESL_IO_MGMT * pIo;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
+ pPort ));
+
+ //
+ // Shutdown the receive operation on the port
+ //
+ if ( NULL != pPort->pfnRxCancel ) {
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ EslSocketRxCancel ( pPort, pIo );
+ pIo = pIo->pNext;
+ }
+ }
+
+ //
+ // Determine if the receive operation is pending
+ //
+ Status = EslSocketPortCloseRxDone ( pPort );
+ DBG_EXIT_STATUS ( Status );
+}
+
+
+/**
+ Port close state 4
+
+ This routine determines the state of the receive operations and
+ continues the close operation after the pending receive operations
+ are cancelled.
+
+ This routine is called by
+ <ul>
+ <li>::EslSocketPortCloseComplete</li>
+ <li>::EslSocketPortCloseTxDone</li>
+ <li>::EslSocketRxComplete</li>
+ </ul>
+ to determine the state of the receive operations.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @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
+EslSocketPortCloseRxDone (
+ IN ESL_PORT * pPort
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Verify that the port is closing
+ //
+ Status = EFI_ALREADY_STARTED;
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
+ //
+ // Determine if the receive operation is pending
+ //
+ Status = EFI_NOT_READY;
+ if ( NULL == pPort->pRxActive ) {
+ //
+ // The receive operation is complete
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_RX_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
+ pPort ));
+
+ //
+ // Complete the port close operation
+ //
+ Status = EslSocketPortClose ( pPort );
+ }
+ else {
+ DEBUG_CODE_BEGIN ();
+ {
+ ESL_IO_MGMT * pIo;
+ //
+ // Display the outstanding receive operations
+ //
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Receive still pending!\r\n",
+ pPort ));
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on network adapter\r\n",
+ pIo->pPacket ));
+ pIo = pIo->pNext;
+ }
+ }
+ DEBUG_CODE_END ( );
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Start the close operation on a port, state 1.
+
+ This routine marks the port as closed and initiates the \ref
+ PortCloseStateMachine. The first step is to allow the \ref
+ TransmitEngine to run down.
+
+ This routine is called by ::EslSocketCloseStart to initiate the socket
+ network specific close operation on the socket.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] bCloseNow Set TRUE to abort active transfers
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port has started the closing process
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseStart (
+ IN ESL_PORT * pPort,
+ IN BOOLEAN bCloseNow,
+ IN UINTN DebugFlags
+ )
+{
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Mark the port as closing
+ //
+ Status = EFI_ALREADY_STARTED;
+ pSocket = pPort->pSocket;
+ pSocket->errno = EALREADY;
+ if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
+
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_STARTED;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
+ pPort ));
+ pPort->bCloseNow = bCloseNow;
+ pPort->DebugFlags = DebugFlags;
+
+ //
+ // Determine if transmits are complete
+ //
+ Status = EslSocketPortCloseTxDone ( pPort );
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 2
+
+ This routine determines the state of the transmit engine and
+ continue the close operation after the transmission is complete.
+ The next step is to stop the \ref ReceiveEngine.
+ See the \ref PortCloseStateMachine section.
+
+ This routine is called by ::EslSocketPortCloseStart to determine
+ if the transmission is complete.
+
+ @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
+EslSocketPortCloseTxDone (
+ IN ESL_PORT * pPort
+ )
+{
+ ESL_IO_MGMT * pIo;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // All transmissions are complete or must be stopped
+ // Mark the port as TX complete
+ //
+ Status = EFI_ALREADY_STARTED;
+ if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
+ //
+ // Verify that the transmissions are complete
+ //
+ pSocket = pPort->pSocket;
+ if ( pPort->bCloseNow
+ || ( EFI_SUCCESS != pSocket->TxError )
+ || (( NULL == pPort->pTxActive )
+ && ( NULL == pPort->pTxOobActive ))) {
+ //
+ // Update the port state
+ //
+ pPort->State = PORT_STATE_CLOSE_TX_DONE;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
+ pPort ));
+
+ //
+ // Close the port
+ // Skip the close operation if the port is not configured
+ //
+ Status = EFI_SUCCESS;
+ pSocket = pPort->pSocket;
+ if (( pPort->bConfigured )
+ && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
+ //
+ // Start the close operation
+ //
+ Status = pSocket->pApi->pfnPortCloseOp ( pPort );
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Close operation still pending!\r\n",
+ pPort ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ else {
+ //
+ // The receive operation is complete
+ // Update the port state
+ //
+ EslSocketPortCloseComplete ( NULL, pPort );
+ }
+ }
+ else {
+ //
+ // Transmissions are still active, exit
+ //
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ DEBUG_CODE_BEGIN ( );
+ {
+ ESL_PACKET * pPacket;
+
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Transmits are still pending!\r\n",
+ pPort ));
+
+ //
+ // Display the pending urgent transmit packets
+ //
+ pPacket = pSocket->pTxOobPacketListHead;
+ while ( NULL != pPacket ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
+ pPacket,
+ pPacket->PacketSize ));
+ pPacket = pPacket->pNext;
+ }
+
+ pIo = pPort->pTxOobActive;
+ while ( NULL != pIo ) {
+ pPacket = pIo->pPacket;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
+ pPacket,
+ pPacket->PacketSize,
+ pIo ));
+ pIo = pIo->pNext;
+ }
+
+ //
+ // Display the pending normal transmit packets
+ //
+ pPacket = pSocket->pTxPacketListHead;
+ while ( NULL != pPacket ) {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
+ pPacket,
+ pPacket->PacketSize ));
+ pPacket = pPacket->pNext;
+ }
+
+ pIo = pPort->pTxActive;
+ while ( NULL != pIo ) {
+ pPacket = pIo->pPacket;
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
+ pPacket,
+ pPacket->PacketSize,
+ pIo ));
+ pIo = pIo->pNext;
+ }
+ }
+ DEBUG_CODE_END ();
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
Receive data from a network connection.
+ This routine calls the network specific routine to remove the
+ next portion of data from the receive queue and return it to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::recvfrom routine calls this routine to determine if any data
+ is received from the remote system. Note that the other routines
+ ::recv and ::read are layered on top of ::recvfrom.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Flags Message control flags
@@ -2506,7 +4263,23 @@ EslSocketReceive (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } Addr;
+ socklen_t AddressLength;
+ BOOLEAN bConsumePacket;
+ BOOLEAN bUrgentQueue;
+ size_t DataLength;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ struct sockaddr * pRemoteAddress;
+ size_t * pRxDataBytes;
+ ESL_SOCKET * pSocket;
+ size_t SkipBytes;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2525,188 +4298,748 @@ EslSocketReceive (
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
//
- // Return the transmit error if necessary
+ // Validate the return address parameters
//
- if ( EFI_SUCCESS != pSocket->TxError ) {
- pSocket->errno = EIO;
- Status = pSocket->TxError;
- pSocket->TxError = EFI_SUCCESS;
- }
- else {
+ if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
//
- // Verify the socket state
+ // Return the transmit error if necessary
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ if ( EFI_SUCCESS != pSocket->TxError ) {
+ pSocket->errno = EIO;
+ Status = pSocket->TxError;
+ pSocket->TxError = EFI_SUCCESS;
+ }
+ else {
//
- // Validate the local address
+ // Verify the socket state
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ Status = EslSocketIsConfigured ( pSocket );
+ if ( !EFI_ERROR ( Status )) {
//
- // Determine the connection point within the network stack
+ // Validate the buffer length
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
+ if (( NULL == pDataLength )
+ || ( NULL == pBuffer )) {
+ if ( NULL == pDataLength ) {
+ DEBUG (( DEBUG_RX,
+ "ERROR - pDataLength is NULL!\r\n" ));
+ }
+ else {
+ DEBUG (( DEBUG_RX,
+ "ERROR - pBuffer is NULL!\r\n" ));
+ }
Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ pSocket->errno = EFAULT;
+ }
+ else {
//
- // Verify the port state
+ // Verify the API
//
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
+ if ( NULL == pSocket->pApi->pfnReceive ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
+ //
+ // Zero the receive address if being returned
+ //
+ pRemoteAddress = NULL;
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (struct sockaddr *)&Addr;
+ ZeroMem ( pRemoteAddress, sizeof ( Addr ));
+ pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
+ pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
+ }
+
+ //
+ // Synchronize with the socket layer
+ //
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+
+ //
+ // 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
+ //
+ bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
+ if ( bUrgentQueue ) {
+ ppQueueHead = &pSocket->pRxOobPacketListHead;
+ ppQueueTail = &pSocket->pRxOobPacketListTail;
+ pRxDataBytes = &pSocket->RxOobBytes;
+ }
+ else {
+ ppQueueHead = &pSocket->pRxPacketListHead;
+ ppQueueTail = &pSocket->pRxPacketListTail;
+ pRxDataBytes = &pSocket->RxBytes;
+ }
+
+ //
+ // Determine if there is any data on the queue
+ //
+ *pDataLength = 0;
+ pPacket = *ppQueueHead;
+ if ( NULL != pPacket ) {
+ //
+ // Copy the received data
+ //
+ do {
+ //
+ // Attempt to receive a packet
+ //
+ SkipBytes = 0;
+ bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
+ pBuffer = pSocket->pApi->pfnReceive ( pPort,
+ pPacket,
+ &bConsumePacket,
+ BufferLength,
+ pBuffer,
+ &DataLength,
+ (struct sockaddr *)&Addr,
+ &SkipBytes );
+ *pDataLength += DataLength;
+ BufferLength -= DataLength;
+
+ //
+ // Determine if the data is being read
+ //
+ pNextPacket = pPacket->pNext;
+ if ( bConsumePacket ) {
+ //
+ // All done with this packet
+ // Account for any discarded data
+ //
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
+ if ( 0 != SkipBytes ) {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
+ pPort,
+ SkipBytes ));
+ }
+
+ //
+ // Remove this packet from the queue
+ //
+ *ppQueueHead = pPacket->pNext;
+ if ( NULL == *ppQueueHead ) {
+ *ppQueueTail = NULL;
+ }
+
+ //
+ // Move the packet to the free queue
+ //
+ pPacket->pNext = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port freeing packet 0x%08x\r\n",
+ pPort,
+ pPacket ));
+
+ //
+ // Restart the receive operation if necessary
+ //
+ if (( NULL != pPort->pRxFree )
+ && ( MAX_RX_DATA > pSocket->RxBytes )) {
+ EslSocketRxStart ( pPort );
+ }
+ }
+
+ //
+ // Get the next packet
+ //
+ pPacket = pNextPacket;
+ } while (( SOCK_STREAM == pSocket->Type )
+ && ( NULL != pPacket )
+ && ( 0 < BufferLength ));
+
+ //
+ // Successful operation
+ //
+ Status = EFI_SUCCESS;
+ pSocket->errno = 0;
+ }
+ else {
+ //
+ // The queue is empty
+ // Determine if it is time to return the receive error
+ //
+ if ( EFI_ERROR ( pSocket->RxError )
+ && ( NULL == pSocket->pRxPacketListHead )
+ && ( NULL == pSocket->pRxOobPacketListHead )) {
+ Status = pSocket->RxError;
+ pSocket->RxError = EFI_SUCCESS;
+ switch ( Status ) {
+ default:
+ pSocket->errno = EIO;
+ break;
+
+ case EFI_CONNECTION_FIN:
+ //
+ // Continue to return zero bytes received when the
+ // peer has successfully closed the connection
+ //
+ pSocket->RxError = EFI_CONNECTION_FIN;
+ *pDataLength = 0;
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ break;
+
+ case EFI_CONNECTION_REFUSED:
+ pSocket->errno = ECONNREFUSED;
+ break;
+
+ case EFI_CONNECTION_RESET:
+ pSocket->errno = ECONNRESET;
+ break;
+
+ case EFI_HOST_UNREACHABLE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
+
+ case EFI_NETWORK_UNREACHABLE:
+ pSocket->errno = ENETUNREACH;
+ break;
+
+ case EFI_PORT_UNREACHABLE:
+ pSocket->errno = EPROTONOSUPPORT;
+ break;
+
+ case EFI_PROTOCOL_UNREACHABLE:
+ pSocket->errno = ENOPROTOOPT;
+ break;
+ }
+ }
+ else {
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ }
+ }
+ }
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+
+ if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
+ //
+ // Return the remote address if requested, truncate if necessary
+ //
+ AddressLength = pRemoteAddress->sa_len;
+ if ( AddressLength > *pAddressLength ) {
+ AddressLength = *pAddressLength;
+ }
+ DEBUG (( DEBUG_RX,
+ "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
+ ZeroMem ( pAddress, *pAddressLength );
+ CopyMem ( pAddress, &Addr, AddressLength );
+
+ //
+ // Update the address length
+ //
+ *pAddressLength = pRemoteAddress->sa_len;
+ }
+ }
+ }
+ }
+ }
+
+
+ }
+ else {
+ //
+ // Bad return address pointer and length
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ if ( NULL != pErrno ) {
+ if ( NULL != pSocket ) {
+ *pErrno = pSocket->errno;
+ }
+ else {
+ Status = EFI_INVALID_PARAMETER;
+ *pErrno = ENOTSOCK;
+ }
+ }
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Cancel the receive operations
+
+ This routine cancels a pending receive operation.
+ See the \ref ReceiveEngine section.
+
+ This routine is called by ::EslSocketShutdown when the socket
+ layer is being shutdown.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+ **/
+VOID
+EslSocketRxCancel (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
+ )
+{
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Cancel the outstanding receive
+ //
+ Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
+ &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
+ pIo->pPacket,
+ pPort ));
+ }
+ else {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
+ pIo->pPacket,
+ pPort,
+ Status ));
+ }
+ DBG_EXIT ( );
+}
+
+
+/**
+ 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 when some data is received by:
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslTcp4RxComplete</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] Status Receive status
+ @param [in] LengthInBytes Length of the receive data
+ @param [in] bUrgent TRUE if urgent data is received and FALSE
+ for normal data.
+
+**/
+VOID
+EslSocketRxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN EFI_STATUS Status,
+ IN UINTN LengthInBytes,
+ IN BOOLEAN bUrgent
+ )
+{
+ BOOLEAN bUrgentQueue;
+ ESL_IO_MGMT * pIoNext;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPrevious;
+ ESL_PACKET ** ppQueueHead;
+ ESL_PACKET ** ppQueueTail;
+ size_t * pRxBytes;
+ ESL_SOCKET * pSocket;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the active receive packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // pPort->pRxActive
+ // |
+ // V
+ // +-------------+ +-------------+ +-------------+
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ //
+ // +-------------+ +-------------+ +-------------+
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ // ^
+ // |
+ // pPort->pRxFree
+ //
+ //
+ // Remove the IO structure from the active list
+ // The following code searches for the entry in the list and does not
+ // assume that the receive operations complete in the order they were
+ // issued to the UEFI network layer.
+ //
+ pIoNext = pPort->pRxActive;
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
+ {
+ pIoNext = pIoNext->pNext;
+ }
+ ASSERT ( NULL != pIoNext );
+ if ( pIoNext == pIo ) {
+ pPort->pRxActive = pIo->pNext; // Beginning of list
+ }
+ else {
+ pIoNext->pNext = pIo->pNext; // Middle of list
+ }
+
+ //
+ // Free the IO structure
+ //
+ pIo->pNext = pPort->pRxFree;
+ pPort->pRxFree = pIo;
+
+ //
+ // pRxOobPacketListHead pRxOobPacketListTail
+ // | |
+ // V V
+ // +------------+ +------------+ +------------+
+ // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ //
+ // +------------+ +------------+ +------------+
+ // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ // ^ ^
+ // | |
+ // pRxPacketListHead pRxPacketListTail
+ //
+ //
+ // Determine the queue to use
+ //
+ bUrgentQueue = (BOOLEAN)( bUrgent
+ && pSocket->pApi->bOobSupported
+ && ( !pSocket->bOobInLine ));
+ if ( bUrgentQueue ) {
+ ppQueueHead = &pSocket->pRxOobPacketListHead;
+ ppQueueTail = &pSocket->pRxOobPacketListTail;
+ pRxBytes = &pSocket->RxOobBytes;
+ }
+ else {
+ ppQueueHead = &pSocket->pRxPacketListHead;
+ ppQueueTail = &pSocket->pRxPacketListTail;
+ pRxBytes = &pSocket->RxBytes;
+ }
+
+ //
+ // Determine if this receive was successful
+ //
+ if (( !EFI_ERROR ( Status ))
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )
+ && ( !pSocket->bRxDisable )) {
+ //
+ // Account for the received data
+ //
+ *pRxBytes += LengthInBytes;
+
+ //
+ // Log the received data
+ //
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
+ pPacket,
+ bUrgentQueue ? L"urgent" : L"normal",
+ pPort,
+ LengthInBytes,
+ bUrgent ? L"urgent" : L"normal" ));
+
+ //
+ // Add the packet to the list tail.
+ //
+ pPacket->pNext = NULL;
+ pPrevious = *ppQueueTail;
+ if ( NULL == pPrevious ) {
+ *ppQueueHead = pPacket;
+ }
+ else {
+ pPrevious->pNext = pPacket;
+ }
+ *ppQueueTail = pPacket;
+
+ //
+ // Attempt to restart this receive operation
+ //
+ if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
+ EslSocketRxStart ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
+ pPort,
+ pSocket->RxBytes ));
+ }
+ }
+ else {
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
+ pPort,
+ pPacket,
+ Status ));
+ }
+
+ //
+ // Account for the receive bytes and release the driver's buffer
+ //
+ if ( !EFI_ERROR ( Status )) {
+ *pRxBytes += LengthInBytes;
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
+ }
+
+ //
+ // Receive error, free the packet save the error
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ if ( !EFI_ERROR ( pSocket->RxError )) {
+ pSocket->RxError = Status;
+ }
+
+ //
+ // Update the port state
+ //
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
+ EslSocketPortCloseRxDone ( pPort );
+ }
+ }
+ else {
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
+ pPort,
+ Status ));
+ pPort->State = PORT_STATE_RX_ERROR;
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Start a receive operation
+
+ This routine posts a receive buffer to the network adapter.
+ See the \ref ReceiveEngine section.
+
+ This support routine is called by:
+ <ul>
+ <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ </ul>
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ **/
+VOID
+EslSocketRxStart (
+ IN ESL_PORT * pPort
+ )
+{
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine if a receive is already pending
+ //
+ Status = EFI_SUCCESS;
+ pPacket = NULL;
+ pSocket = pPort->pSocket;
+ if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
+ if (( NULL != pPort->pRxFree )
+ && ( !pSocket->bRxDisable )
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
+ //
+ // Start all of the pending receive operations
+ //
+ while ( NULL != pPort->pRxFree ) {
+ //
+ // Determine if there are any free packets
+ //
+ pPacket = pSocket->pRxFree;
+ if ( NULL != pPacket ) {
+ //
+ // Remove this packet from the free list
+ //
+ pSocket->pRxFree = pPacket->pNext;
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port removed packet 0x%08x from free list\r\n",
+ pPort,
+ pPacket ));
+ }
+ else {
+ //
+ // Allocate a packet structure
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ pSocket->pApi->RxPacketBytes,
+ pSocket->pApi->RxZeroBytes,
+ DEBUG_RX );
+ if ( EFI_ERROR ( Status )) {
+ pPacket = NULL;
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
+ pPort,
+ Status ));
break;
}
- break;
}
//
- // Release the socket layer synchronization
+ // Connect the IO and packet structures
//
- RESTORE_TPL ( TplPrevious );
+ pIo = pPort->pRxFree;
+ pIo->pPacket = pPacket;
//
- // Set errno if a failure occurs
+ // Eliminate the need for IP4 and UDP4 specific routines by
+ // clearing the RX data pointer here.
//
- if ( EFI_ERROR ( Status )) {
- pSocket->errno = EADDRNOTAVAIL;
- }
- }
- if ( !EFI_ERROR ( Status )) {
+ // No driver buffer for this packet
//
- // Validate the buffer length
+ // +--------------------+
+ // | ESL_IO_MGMT |
+ // | |
+ // | +---------------+
+ // | | Token |
+ // | | RxData --> NULL
+ // +----+---------------+
//
- if (( NULL == pDataLength )
- && ( 0 > pDataLength )
- && ( NULL == pBuffer )) {
- if ( NULL == pDataLength ) {
- DEBUG (( DEBUG_RX,
- "ERROR - pDataLength is NULL!\r\n" ));
- }
- else if ( NULL == pBuffer ) {
- DEBUG (( DEBUG_RX,
- "ERROR - pBuffer is NULL!\r\n" ));
- }
- else {
- DEBUG (( DEBUG_RX,
- "ERROR - Data length < 0!\r\n" ));
- }
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EFAULT;
+ pBuffer = (UINT8 *)pIo;
+ pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
+ *(VOID **)pBuffer = NULL;
+
+ //
+ // Network specific receive packet initialization
+ //
+ if ( NULL != pSocket->pApi->pfnRxStart ) {
+ pSocket->pApi->pfnRxStart ( pPort, pIo );
}
- else{
+
+ //
+ // Start the receive on the packet
+ //
+ Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet receive pending on port 0x%08x\r\n",
+ pPacket,
+ pPort ));
//
- // Synchronize with the socket layer
+ // Allocate the receive control structure
//
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
+ pPort->pRxFree = pIo->pNext;
+
//
- // Validate the local address
+ // Mark this receive as pending
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ pIo->pNext = pPort->pRxActive;
+ pPort->pRxActive = pIo;
+
+ }
+ else {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
+ if ( !EFI_ERROR ( pSocket->RxError )) {
//
- // Determine the connection point within the network stack
+ // Save the error status
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpReceive4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- pAddressLength );
- break;
-
- case SOCK_DGRAM:
- Status = EslUdpReceive4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- pAddressLength);
- break;
- }
- break;
+ pSocket->RxError = Status;
}
//
- // Release the socket layer synchronization
+ // Free the packet
//
- RESTORE_TPL ( TplPrevious );
+ pIo->pPacket = NULL;
+ pPacket->pNext = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket;
+ break;
}
}
}
- }
-
- //
- // Return the operation status
- //
- if ( NULL != pErrno ) {
- if ( NULL != pSocket ) {
- *pErrno = pSocket->errno;
- }
- else
- {
- Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ else {
+ if ( NULL == pPort->pRxFree ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
+ pPort));
+ }
+ if ( pSocket->bRxDisable ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, receive disabled!\r\n",
+ pPort ));
+ }
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Port, is closing!\r\n",
+ pPort ));
+ }
}
}
- DBG_EXIT_STATUS ( Status );
- return Status;
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,
+ "ERROR - Previous receive error, Status: %r\r\n",
+ pPort->pSocket->RxError ));
+ }
+
+ DBG_EXIT ( );
}
/**
Shutdown the socket receive and transmit operations
- The SocketShutdown routine stops the socket receive and transmit
- operations.
+ This routine sets a flag to stop future transmissions and calls
+ the network specific layer to cancel the pending receive operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::shutdown routine calls this routine to stop receive and transmit
+ operations on the socket.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] How Which operations to stop
@@ -2722,7 +5055,9 @@ EslSocketShutdown (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_IO_MGMT * pIo;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2768,47 +5103,29 @@ EslSocketShutdown (
}
//
- // Validate the local address
+ // Cancel the pending receive operations
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( pSocket->bRxDisable ) {
//
- // Determine the connection point within the network stack
+ // Walk the list of ports
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
//
- // Cancel the pending receive operation
+ // Walk the list of active receive operations
//
- Status = EslTcpRxCancel4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
+ pIo = pPort->pRxActive;
+ while ( NULL != pIo ) {
+ EslSocketRxCancel ( pPort, pIo );
+ }
+
//
- // Cancel the pending receive operation
+ // Set the next port
//
- Status = EslUdpRxCancel4 ( pSocket );
- break;
+ pPort = pPort->pLinkSocket;
}
- break;
}
-
+
//
// Release the socket layer synchronization
//
@@ -2816,18 +5133,18 @@ EslSocketShutdown (
}
else {
//
- // The socket is not connected
+ // Invalid How value
//
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
}
}
else {
//
- // Invalid How value
+ // The socket is not connected
//
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
}
}
@@ -2838,10 +5155,9 @@ EslSocketShutdown (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -2852,10 +5168,17 @@ EslSocketShutdown (
/**
Send data using a network connection.
- The SocketTransmit routine queues the data for transmission to the
- remote network connection.
+ This routine calls the network specific layer to queue the data
+ for transmission. Eventually the buffer will reach the head of
+ the queue and will get transmitted over the network by the
+ \ref TransmitEngine. For datagram
+ sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
+ the data reaches the application running on the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::sendto routine calls this routine to send data to the remote
+ system. Note that ::send and ::write are layered on top of ::sendto.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Flags Message control flags
@@ -2886,7 +5209,7 @@ EslSocketTransmit (
IN int * pErrno
)
{
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2916,66 +5239,7 @@ EslSocketTransmit (
//
// Verify the socket state
//
- if ( !pSocket->bConfigured ) {
- //
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
- //
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
- //
- // Determine the connection point within the network stack
- //
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- break;
-
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- //
- // Verify the port state
- //
- Status = EslTcpSocketIsConfigured4 ( pSocket );
- break;
-
- case SOCK_DGRAM:
- //
- // Verify the port state
- //
- Status = EslUdpSocketIsConfigured4 ( pSocket );
- break;
- }
- break;
- }
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
-
- //
- // Set errno if a failure occurs
- //
- if ( EFI_ERROR ( Status )) {
- pSocket->errno = EADDRNOTAVAIL;
- }
- }
+ Status = EslSocketIsConfigured ( pSocket );
if ( !EFI_ERROR ( Status )) {
//
// Verify that transmit is still allowed
@@ -3015,61 +5279,34 @@ EslSocketTransmit (
}
else {
//
- // Synchronize with the socket layer
- //
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );
-
- //
- // Validate the local address
+ // Verify the API
//
- switch ( pSocket->Domain ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket address family: %d\r\n",
- pSocket->Domain ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
-
- case AF_INET:
+ if ( NULL == pSocket->pApi->pfnTransmit ) {
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTSUP;
+ }
+ else {
//
- // Determine the connection point within the network stack
+ // Synchronize with the socket layer
//
- switch ( pSocket->Type ) {
- default:
- DEBUG (( DEBUG_RX,
- "ERROR - Invalid socket type: %d\r\n",
- pSocket->Type));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EADDRNOTAVAIL;
- break;
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- Status = EslTcpTxBuffer4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength );
- break;
+ //
+ // Attempt to buffer the packet for transmission
+ //
+ Status = pSocket->pApi->pfnTransmit ( pSocket,
+ Flags,
+ BufferLength,
+ pBuffer,
+ pDataLength,
+ pAddress,
+ AddressLength );
- case SOCK_DGRAM:
- Status = EslUdpTxBuffer4 ( pSocket,
- Flags,
- BufferLength,
- pBuffer,
- pDataLength,
- pAddress,
- AddressLength );
- break;
- }
- break;
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
}
-
- //
- // Release the socket layer synchronization
- //
- RESTORE_TPL ( TplPrevious );
}
}
}
@@ -3091,10 +5328,9 @@ EslSocketTransmit (
if ( NULL != pSocket ) {
*pErrno = pSocket->errno;
}
- else
- {
+ else {
Status = EFI_INVALID_PARAMETER;
- *pErrno = EBADF;
+ *pErrno = ENOTSOCK;
}
}
DBG_EXIT_STATUS ( Status );
@@ -3103,9 +5339,325 @@ EslSocketTransmit (
/**
- Socket layer's service binding protocol delcaration.
-**/
-EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {
- EslSocketCreateChild,
- EslSocketDestroyChild
-};
+ Complete the transmit operation
+
+ This support routine handles the transmit completion processing for
+ the various network layers. It frees the ::ESL_IO_MGMT structure
+ and and frees packet resources by calling ::EslSocketPacketFree.
+ Transmit errors are logged in ESL_SOCKET::TxError.
+ See the \ref TransmitEngine section.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4TxComplete</li>
+ <li>::EslTcp4TxComplete</li>
+ <li>::EslTcp4TxOobComplete</li>
+ <li>::EslUdp4TxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] LengthInBytes Length of the data in bytes
+ @param [in] Status Transmit operation status
+ @param [in] pQueueType Zero terminated string describing queue type
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
+
+ **/
+VOID
+EslSocketTxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN UINT32 LengthInBytes,
+ IN EFI_STATUS Status,
+ IN CONST CHAR8 * pQueueType,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
+ )
+{
+ ESL_PACKET * pCurrentPacket;
+ ESL_IO_MGMT * pIoNext;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
+
+ DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
+
+ //
+ // Locate the active transmit packet
+ //
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
+ pSocket = pPort->pSocket;
+
+ //
+ // No more packet
+ //
+ pIo->pPacket = NULL;
+
+ //
+ // Remove the IO structure from the active list
+ //
+ pIoNext = *ppActive;
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
+ {
+ pIoNext = pIoNext->pNext;
+ }
+ ASSERT ( NULL != pIoNext );
+ if ( pIoNext == pIo ) {
+ *ppActive = pIo->pNext; // Beginning of list
+ }
+ else {
+ pIoNext->pNext = pIo->pNext; // Middle of list
+ }
+
+ //
+ // Free the IO structure
+ //
+ pIo->pNext = *ppFree;
+ *ppFree = pIo;
+
+ //
+ // Display the results
+ //
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: pIo Released\r\n",
+ pIo ));
+
+ //
+ // Save any transmit error
+ //
+ if ( EFI_ERROR ( Status )) {
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ pSocket->TxError = Status;
+ }
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
+ pQueueType,
+ pPacket,
+ Status ));
+
+ //
+ // Empty the normal transmit list
+ //
+ pCurrentPacket = pPacket;
+ pNextPacket = *ppQueueHead;
+ while ( NULL != pNextPacket ) {
+ pPacket = pNextPacket;
+ pNextPacket = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+ *ppQueueHead = NULL;
+ *ppQueueTail = NULL;
+ pPacket = pCurrentPacket;
+ }
+ else {
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: %apacket transmitted %d bytes successfully\r\n",
+ pPacket,
+ pQueueType,
+ LengthInBytes ));
+
+ //
+ // Verify the transmit engine is still running
+ //
+ if ( !pPort->bCloseNow ) {
+ //
+ // Start the next packet transmission
+ //
+ EslSocketTxStart ( pPort,
+ ppQueueHead,
+ ppQueueTail,
+ ppActive,
+ ppFree );
+ }
+ }
+
+ //
+ // Release this packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+
+ //
+ // Finish the close operation if necessary
+ //
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
+ //
+ // Indicate that the transmit is complete
+ //
+ EslSocketPortCloseTxDone ( pPort );
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Transmit data using a network connection.
+
+ This support routine starts a transmit operation on the
+ underlying network layer.
+
+ The network specific code calls this routine to start a
+ transmit operation. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
+
+ **/
+VOID
+EslSocketTxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
+ )
+{
+ UINT8 * pBuffer;
+ ESL_IO_MGMT * pIo;
+ ESL_PACKET * pNextPacket;
+ ESL_PACKET * pPacket;
+ VOID ** ppTokenData;
+ ESL_SOCKET * pSocket;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the packet from the queue head
+ //
+ pPacket = *ppQueueHead;
+ pIo = *ppFree;
+ if (( NULL != pPacket ) && ( NULL != pIo )) {
+ pSocket = pPort->pSocket;
+ //
+ // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
+ // |
+ // V
+ // +------------+ +------------+ +------------+
+ // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
+ // +------------+ +------------+ +------------+
+ // ^
+ // |
+ // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
+ //
+ //
+ // Remove the packet from the queue
+ //
+ pNextPacket = pPacket->pNext;
+ *ppQueueHead = pNextPacket;
+ if ( NULL == pNextPacket ) {
+ *ppQueueTail = NULL;
+ }
+ pPacket->pNext = NULL;
+
+ //
+ // Eliminate the need for IP4 and UDP4 specific routines by
+ // connecting the token with the TX data control structure here.
+ //
+ // +--------------------+ +--------------------+
+ // | ESL_IO_MGMT | | ESL_PACKET |
+ // | | | |
+ // | +---------------+ +----------------+ |
+ // | | Token | | Buffer Length | |
+ // | | TxData --> | Buffer Address | |
+ // | | | +----------------+---+
+ // | | Event | | Data Buffer |
+ // +----+---------------+ | |
+ // +--------------------+
+ //
+ // Compute the address of the TxData pointer in the token
+ //
+ pBuffer = (UINT8 *)&pIo->Token;
+ pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
+ ppTokenData = (VOID **)pBuffer;
+
+ //
+ // Compute the address of the TX data control structure in the packet
+ //
+ // * EFI_IP4_TRANSMIT_DATA
+ // * EFI_TCP4_TRANSMIT_DATA
+ // * EFI_UDP4_TRANSMIT_DATA
+ //
+ pBuffer = (UINT8 *)pPacket;
+ pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
+
+ //
+ // Connect the token to the transmit data control structure
+ //
+ *ppTokenData = (VOID **)pBuffer;
+
+ //
+ // Display the results
+ //
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
+ pIo,
+ pPacket ));
+
+ //
+ // Start the transmit operation
+ //
+ Status = pPort->pfnTxStart ( pPort->pProtocol.v,
+ &pIo->Token );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Connect the structures
+ //
+ pIo->pPacket = pPacket;
+
+ //
+ // +-------------+ +-------------+ +-------------+
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ // ^
+ // |
+ // *ppFree: pPort->pTxFree or pTxOobFree
+ //
+ //
+ // Remove the IO structure from the queue
+ //
+ *ppFree = pIo->pNext;
+
+ //
+ // *ppActive: pPort->pTxActive or pTxOobActive
+ // |
+ // V
+ // +-------------+ +-------------+ +-------------+
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
+ // +-------------+ +-------------+ +-------------+
+ //
+ //
+ // Mark this packet as active
+ //
+ pIo->pPacket = pPacket;
+ pIo->pNext = *ppActive;
+ *ppActive = pIo;
+ }
+ else {
+ if ( EFI_SUCCESS == pSocket->TxError ) {
+ pSocket->TxError = Status;
+ }
+
+ //
+ // Discard the transmit buffer
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+ }
+
+ DBG_EXIT ( );
+}
diff --git a/StdLib/EfiSocketLib/Socket.h b/StdLib/EfiSocketLib/Socket.h
index 42377eb29c..25133e6f89 100644
--- a/StdLib/EfiSocketLib/Socket.h
+++ b/StdLib/EfiSocketLib/Socket.h
@@ -30,27 +30,26 @@
#define DEBUG_TX 0x00400000 ///< Display transmit messages
#define DEBUG_CLOSE 0x00200000 ///< Display close messages
#define DEBUG_CONNECT 0x00100000 ///< Display connect messages
+#define DEBUG_OPTION 0x00080000 ///< Display option messages
#define MAX_PENDING_CONNECTIONS 1 ///< Maximum connection FIFO depth
#define MAX_RX_DATA 65536 ///< Maximum receive data size
-#define MAX_TX_DATA ( MAX_RX_DATA * 2 )
+#define MAX_TX_DATA ( MAX_RX_DATA * 2 ) ///< Maximum buffered transmit data in bytes
#define RX_PACKET_DATA 16384 ///< Maximum number of bytes in a RX packet
+#define MAX_UDP_RETRANSMIT 16 ///< UDP retransmit attempts to handle address not mapped
-#define LAYER_SIGNATURE SIGNATURE_32('S','k','t','L') ///< DT_LAYER memory signature
-#define SERVICE_SIGNATURE SIGNATURE_32('S','k','t','S') ///< DT_SERVICE memory signature
-#define SOCKET_SIGNATURE SIGNATURE_32('S','c','k','t') ///< DT_SOCKET memory signature
-#define PORT_SIGNATURE SIGNATURE_32('P','o','r','t') ///< DT_PORT memory signature
+#define ESL_STRUCTURE_ALIGNMENT_BYTES 15 ///< Number of bytes for structure alignment
+#define ESL_STRUCTURE_ALIGNMENT_MASK ( ~ESL_STRUCTURE_ALIGNMENT_BYTES ) ///< Mask to align structures
+
+#define LAYER_SIGNATURE SIGNATURE_32 ('S','k','t','L') ///< ESL_LAYER memory signature
+#define SERVICE_SIGNATURE SIGNATURE_32 ('S','k','t','S') ///< ESL_SERVICE memory signature
+#define SOCKET_SIGNATURE SIGNATURE_32 ('S','c','k','t') ///< ESL_SOCKET memory signature
+#define PORT_SIGNATURE SIGNATURE_32 ('P','o','r','t') ///< ESL_PORT memory signature
-typedef enum
-{
- NETWORK_TYPE_UNKNOWN = 0,
- NETWORK_TYPE_RAW,
- NETWORK_TYPE_TCP4,
- NETWORK_TYPE_TCP6,
- NETWORK_TYPE_UDP4,
- NETWORK_TYPE_UDP6
-} NETWORK_TYPE;
+/**
+ Socket states
+**/
typedef enum
{
SOCKET_STATE_NOT_CONFIGURED = 0, ///< socket call was successful
@@ -67,6 +66,10 @@ typedef enum
SOCKET_STATE_CLOSED ///< Close call was successful
} SOCKET_STATE;
+
+/**
+ Port states
+**/
typedef enum
{
PORT_STATE_ALLOCATED = 0, ///< Port allocated
@@ -74,102 +77,164 @@ typedef enum
PORT_STATE_RX_ERROR, ///< Receive error detected
//
- // Close state must be last in the list
+ // Close state must be last in the list!
+ //
+ // Using < <= > >= in tests code to detect port close state
+ // machine has started
//
PORT_STATE_CLOSE_STARTED, ///< Close started on port
PORT_STATE_CLOSE_TX_DONE, ///< Transmits shutdown
- PORT_STATE_CLOSE_RX_DONE, ///< Receives shutdown
- PORT_STATE_CLOSE_DONE ///< Port close operation complete
+ PORT_STATE_CLOSE_DONE, ///< Port close operation complete
+ PORT_STATE_CLOSE_RX_DONE ///< Receives shutdown
} PORT_STATE;
//------------------------------------------------------------------------------
// Data Types
//------------------------------------------------------------------------------
-typedef struct _DT_PACKET DT_PACKET; ///< Forward declaration
-typedef struct _DT_PORT DT_PORT; ///< Forward declaration
-typedef struct _DT_SOCKET DT_SOCKET; ///< Forward declaration
+typedef struct _ESL_IO_MGMT ESL_IO_MGMT;///< Forward declaration
+typedef struct _ESL_PACKET ESL_PACKET; ///< Forward declaration
+typedef struct _ESL_PORT ESL_PORT; ///< Forward declaration
+typedef struct _ESL_SOCKET ESL_SOCKET; ///< Forward declaration
+/**
+ Receive context for SOCK_RAW sockets using IPv4.
+**/
+typedef struct
+{
+ EFI_IP4_RECEIVE_DATA * pRxData; ///< Receive operation description
+} ESL_IP4_RX_DATA;
+
+
+/**
+ Transmit context for SOCK_RAW sockets using IPv4.
+**/
+typedef struct
+{
+ EFI_IP4_OVERRIDE_DATA Override; ///< Override data
+ EFI_IP4_TRANSMIT_DATA TxData; ///< Transmit operation description
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_IP4_TX_DATA;
+
+
+/**
+ Receive context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv4.
+**/
typedef struct
{
EFI_TCP4_RECEIVE_DATA RxData; ///< Receive operation description
- size_t ValidBytes; ///< Length of valid data in bytes
- UINT8 * pBuffer; ///< Current data pointer
- UINT8 Buffer [ RX_PACKET_DATA ]; ///< Data buffer
-} DT_TCP4_RX_DATA;
+ UINT8 Buffer[ RX_PACKET_DATA ]; ///< Data buffer
+} ESL_TCP4_RX_DATA;
+
+/**
+ Transmit context for SOCK_STREAM and SOCK_SEQPACKET sockets using TCPv4.
+**/
typedef struct
{
EFI_TCP4_TRANSMIT_DATA TxData; ///< Transmit operation description
- UINT8 Buffer [ 1 ]; ///< Data buffer
-} DT_TCP4_TX_DATA;
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_TCP4_TX_DATA;
+
+/**
+ Receive context for SOCK_DGRAM sockets using UDPv4.
+**/
typedef struct
{
- EFI_UDP4_SESSION_DATA Session; ///< * Remote network address
- EFI_UDP4_RECEIVE_DATA * pRxData; ///< * Receive operation description
-} DT_UDP4_RX_DATA;
+ EFI_UDP4_SESSION_DATA Session; ///< Remote network address
+ EFI_UDP4_RECEIVE_DATA * pRxData; ///< Receive operation description
+} ESL_UDP4_RX_DATA;
+
+/**
+ Transmit context for SOCK_DGRAM sockets using UDPv4.
+**/
typedef struct
{
EFI_UDP4_SESSION_DATA Session; ///< Remote network address
EFI_UDP4_TRANSMIT_DATA TxData; ///< Transmit operation description
- UINT8 Buffer [ 1 ]; ///< Data buffer
-} DT_UDP4_TX_DATA;
+ UINTN RetransmitCount; ///< Retransmit to handle ARP negotiation
+ UINT8 Buffer[ 1 ]; ///< Data buffer
+} ESL_UDP4_TX_DATA;
+
-typedef struct _DT_PACKET {
- DT_PACKET * pNext; ///< Next packet in the receive list
+/**
+ Network specific context for transmit and receive packets.
+**/
+typedef struct _ESL_PACKET {
+ ESL_PACKET * pNext; ///< Next packet in the receive list
size_t PacketSize; ///< Size of this data structure
+ size_t ValidBytes; ///< Length of valid data in bytes
+ UINT8 * pBuffer; ///< Current data pointer
union {
- DT_TCP4_RX_DATA Tcp4Rx; ///< Receive operation description
- DT_TCP4_TX_DATA Tcp4Tx; ///< Transmit operation description
- DT_UDP4_RX_DATA Udp4Rx; ///< Receive operation description
- DT_UDP4_TX_DATA Udp4Tx; ///< Transmit operation description
- } Op;
-} GCC_DT_PACKET;
+ ESL_IP4_RX_DATA Ip4Rx; ///< Receive operation description
+ 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_UDP4_RX_DATA Udp4Rx; ///< Receive operation description
+ ESL_UDP4_TX_DATA Udp4Tx; ///< Transmit operation description
+ } Op; ///< Network specific context
+} GCC_ESL_PACKET;
/**
Service control structure
The driver uses this structure to manage the network devices.
**/
-typedef struct _DT_SERVICE {
+typedef struct _ESL_SERVICE {
UINTN Signature; ///< Structure identification
//
// Links
//
- DT_SERVICE * pNext; ///< Next service in the service list
+ ESL_SERVICE * pNext; ///< Next service in the service list
//
// Service data
//
- CONST DT_SOCKET_BINDING * pSocketBinding; ///< Name and shutdown routine
- EFI_HANDLE Controller; ///< Controller for the service
- VOID * pInterface; ///< Network layer service binding interface
+ CONST ESL_SOCKET_BINDING * pSocketBinding; ///< Name and shutdown routine
+ EFI_HANDLE Controller; ///< Controller for the service
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Network layer service binding interface
//
// Network data
//
- NETWORK_TYPE NetworkType; ///< Type of network service
- DT_PORT * pPortList; ///< List of ports using this service
-}GCC_DT_SERVICE;
+ ESL_PORT * pPortList; ///< List of ports using this service
+}GCC_ESL_SERVICE;
/**
- Start the close operation on a TCP4 port.
+ IO management structure
- @param [in] pPort Address of the port structure.
- @param [in] bAbort Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This structure manages a single operation with the network.
+**/
+typedef struct _ESL_IO_MGMT {
+ ESL_IO_MGMT * pNext; ///< Next TX management structure
+ ESL_PORT * pPort; ///< Port structure address
+ ESL_PACKET * pPacket; ///< Packet structure address
+ union {
+ EFI_IP4_COMPLETION_TOKEN Ip4Rx; ///< IP4 receive token
+ 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_UDP4_COMPLETION_TOKEN Udp4Rx; ///< UDP4 receive token
+ EFI_UDP4_COMPLETION_TOKEN Udp4Tx; ///< UDP4 transmit token
+ } Token; ///< Completion token for the network operation
+};
+
+/**
+ IP4 context structure
+ The driver uses this structure to manage the IP4 connections.
**/
-typedef
-EFI_STATUS
-PFN_PORT_CLOSE_START (
- IN DT_PORT * pPort,
- IN BOOLEAN bAbort,
- IN UINTN DebugFlags
- );
+typedef struct {
+ //
+ // IP4 context
+ //
+ EFI_IP4_MODE_DATA ModeData; ///< IP4 mode data, includes configuration data
+ EFI_IPv4_ADDRESS DestinationAddress; ///< Default destination address
+} ESL_IP4_CONTEXT;
+
/**
TCP4 context structure
@@ -180,34 +245,16 @@ typedef struct {
//
// TCP4 context
//
- EFI_HANDLE Handle; ///< TCP4 port handle
- EFI_TCP4_PROTOCOL * pProtocol; ///< TCP4 protocol pointer
- EFI_TCP4_CONFIG_DATA ConfigData; ///< TCP4 configuration data
- EFI_TCP4_OPTION Option; ///< TCP4 port options
- BOOLEAN bConfigured; ///< TRUE if configuration was successful
+ EFI_TCP4_CONFIG_DATA ConfigData; ///< TCP4 configuration data
+ EFI_TCP4_OPTION Option; ///< TCP4 port options
//
// Tokens
//
- EFI_TCP4_LISTEN_TOKEN ListenToken; ///< Listen control
+ EFI_TCP4_LISTEN_TOKEN ListenToken; ///< Listen control
EFI_TCP4_CONNECTION_TOKEN ConnectToken; ///< Connection control
- EFI_TCP4_CLOSE_TOKEN CloseToken; ///< Close control
-
- //
- // Receive data management
- //
- EFI_TCP4_IO_TOKEN RxToken; ///< Receive token
- DT_PACKET * pReceivePending; ///< Receive operation in progress
-
- //
- // Transmit data management
- //
- EFI_TCP4_IO_TOKEN TxOobToken; ///< Urgent data token
- DT_PACKET * pTxOobPacket; ///< Urgent data in progress
-
- EFI_TCP4_IO_TOKEN TxToken; ///< Normal data token
- DT_PACKET * pTxPacket; ///< Normal transmit in progress
-} DT_TCP4_CONTEXT;
+ EFI_TCP4_CLOSE_TOKEN CloseToken; ///< Close control
+} ESL_TCP4_CONTEXT;
/**
UDP4 context structure
@@ -218,24 +265,41 @@ typedef struct {
//
// UDP4 context
//
- EFI_HANDLE Handle; ///< UDP4 port handle
- EFI_UDP4_PROTOCOL * pProtocol; ///< UDP4 protocol pointer
EFI_UDP4_CONFIG_DATA ConfigData; ///< UDP4 configuration data
- BOOLEAN bConfigured; ///< TRUE if configuration was successful
+} ESL_UDP4_CONTEXT;
- //
- // Receive data management
- //
- EFI_UDP4_COMPLETION_TOKEN RxToken;///< Receive token
- DT_PACKET * pReceivePending; ///< Receive operation in progress
- //
- // Transmit data management
- //
- EFI_UDP4_COMPLETION_TOKEN TxToken;///< Transmit token
- DT_PACKET * pTxPacket; ///< Transmit in progress
-} DT_UDP4_CONTEXT;
+/**
+ Configure the network layer.
+
+ @param [in] pProtocol Protocol structure address
+ @param [in] pConfigData Address of the confiuration data
+
+ @return Returns EFI_SUCCESS if the operation is successfully
+ started.
+**/
+typedef
+EFI_STATUS
+(* PFN_NET_CONFIGURE) (
+ IN VOID * pProtocol,
+ IN VOID * pConfigData
+ );
+
+/**
+ Hand an I/O operation to the network layer.
+
+ @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_IO_START) (
+ IN VOID * pProtocol,
+ IN VOID * pToken
+ );
/**
Port control structure
@@ -243,240 +307,75 @@ typedef struct {
The driver uses this structure to manager the socket's connection
with the network driver.
**/
-typedef struct _DT_PORT {
+typedef struct _ESL_PORT {
UINTN Signature; ///< Structure identification
//
// List links
//
- DT_PORT * pLinkService; ///< Link in service port list
- DT_PORT * pLinkSocket; ///< Link in socket port list
+ ESL_PORT * pLinkService; ///< Link in service port list
+ ESL_PORT * pLinkSocket; ///< Link in socket port list
//
// Structures
//
- DT_SERVICE * pService; ///< Service for this port
- DT_SOCKET * pSocket; ///< Socket for this port
-// PFN_CLOSE_PORT pfnClosePort; ///< Routine to immediately close the port
- PFN_PORT_CLOSE_START * pfnCloseStart; ///< Routine to start closing the port
-
- //
- // Protocol specific management data
- //
- PORT_STATE State; ///< State of the port
- UINTN DebugFlags; ///< Debug flags used to close the port
- BOOLEAN bCloseNow; ///< TRUE = Close the port immediately
-
- union {
- DT_TCP4_CONTEXT Tcp4; ///< TCPv4 management data
- DT_UDP4_CONTEXT Udp4; ///< UDPv4 management data
- } Context;
-}GCC_DT_PORT;
-
-/**
- Socket control structure
-
- The driver uses this structure to manage the socket.
-**/
-typedef struct _DT_SOCKET {
- UINTN Signature; ///< Structure identification
-
- //
- // Protocol binding
- //
- EFI_SOCKET_PROTOCOL SocketProtocol; ///< Socket protocol declaration
+ ESL_SERVICE * pService; ///< Service for this port
+ ESL_SOCKET * pSocket; ///< Socket for this port
//
- // Socket management
+ // Eliminate the pService references during port close
//
- DT_SOCKET * pNext; ///< Next socket in the list of sockets
- int errno; ///< Error information for this socket
- EFI_STATUS Status; ///< Asyncronous error information for this socket
- SOCKET_STATE State; ///< Socket state
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Service binding for network layer
+ CONST ESL_SOCKET_BINDING * pSocketBinding; ///< Socket binding for network layer
//
- // Socket data
+ // Port management
//
- int Domain; ///< Specifies family of protocols
- int Type; ///< Specifies how to make network connection
- int Protocol; ///< Specifies lower layer protocol to use
- BOOLEAN bConfigured; ///< Set after the socket is configured
-
- BOOLEAN bRxDisable; ///< Receive disabled via shutdown
- size_t RxBytes; ///< Total Rx bytes
- size_t RxOobBytes; ///< Urgent Rx bytes
- EFI_STATUS RxError; ///< Error during receive
-
- BOOLEAN bTxDisable; ///< Transmit disabled via shutdown
- size_t TxBytes; ///< Normal Tx bytes
- size_t TxOobBytes; ///< Urgent Tx bytes
- EFI_STATUS TxError; ///< Error during transmit
-
- //
- // Pending connection data
- //
- BOOLEAN bConnected; ///< Set when connected, cleared by poll
- EFI_STATUS ConnectStatus; ///< Connection status
- UINTN MaxFifoDepth; ///< Maximum FIFO depth
- UINTN FifoDepth; ///< Number of sockets in the FIFO
- DT_SOCKET * pFifoHead; ///< Head of the FIFO
- DT_SOCKET * pFifoTail; ///< Tail of the FIFO
- DT_SOCKET * pNextConnection; ///< Link in the FIFO
-
- //
- // Network use
- //
- DT_PORT * pPortList; ///< List of ports managed by this socket
- EFI_EVENT WaitAccept; ///< Wait for accept completion
-
- //
- // Receive data management
- //
- UINT32 MaxRxBuf; ///< Maximum size of the receive buffer
- struct timeval RxTimeout; ///< Receive timeout
- DT_PACKET * pRxFree; ///< Free packet list
- DT_PACKET * pRxOobPacketListHead; ///< Urgent data list head
- DT_PACKET * pRxOobPacketListTail; ///< Urgent data list tail
- DT_PACKET * pRxPacketListHead; ///< Normal data list head
- DT_PACKET * pRxPacketListTail; ///< Normal data list tail
+ EFI_HANDLE Handle; ///< Network port handle
+ PORT_STATE State; ///< State of the port
+ UINTN DebugFlags; ///< Debug flags used to close the port
+ BOOLEAN bCloseNow; ///< TRUE = Close the port immediately
+ BOOLEAN bConfigured; ///< TRUE = Configure call made to network layer
+ PFN_NET_CONFIGURE pfnConfigure; ///< Configure the network layer
//
// Transmit data management
//
- UINT32 MaxTxBuf; ///< Maximum size of the transmit buffer
- DT_PACKET * pTxOobPacketListHead; ///< Urgent data list head
- DT_PACKET * pTxOobPacketListTail; ///< Urgent data list tail
- DT_PACKET * pTxPacketListHead; ///< Normal data list head
- DT_PACKET * pTxPacketListTail; ///< Normal data list tail
-}GCC_DT_SOCKET;
-
-#define SOCKET_FROM_PROTOCOL(a) CR(a, DT_SOCKET, SocketProtocol, SOCKET_SIGNATURE) ///< Locate DT_SOCKET from protocol
-
-/**
- Socket layer control structure
-
- The driver uses this structure to manage the driver.
-**/
-typedef struct {
- UINTN Signature; ///< Structure identification
-
- //
- // Service binding interface
- //
- EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;///< Driver's binding
+ BOOLEAN bTxFlowControl; ///< TX flow control applied
+ PFN_NET_IO_START pfnTxStart; ///< Start a transmit on the network
+ ESL_IO_MGMT * pTxActive; ///< Normal data queue
+ ESL_IO_MGMT * pTxFree; ///< Normal free queue
- //
- // Image data
- //
- EFI_HANDLE ImageHandle; ///< Image handle
+ ESL_IO_MGMT * pTxOobActive; ///< Urgent data queue
+ ESL_IO_MGMT * pTxOobFree; ///< Urgent free queue
//
- // Network services
+ // Receive data management
//
- DT_SERVICE * pTcp4List; ///< List of Tcp4 services
- DT_SERVICE * pUdp4List; ///< List of Udp4 services
+ PFN_NET_IO_START pfnRxCancel; ///< Cancel a receive on the network
+ 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
//
- // Socket management
- //
- DT_SOCKET * pSocketList; ///< List of sockets
-
- //
- // TCP4 service
+ // Protocol specific management data
//
- UINTN TcpCloseMax4; ///< Number of entries in the ring buffer
- UINTN TcpCloseIn4; ///< Offset into TcpClose4 ring buffer - Close request
- UINTN TcpCloseOut4; ///< Offset into TcpClose4 ring buffer - Close operation
- EFI_TCP4_PROTOCOL ** ppTcpClose4; ///< Ring buffer to close TCP4 ports
-} DT_LAYER;
-
-#define LAYER_FROM_SERVICE(a) CR(a, DT_LAYER, ServiceBinding, LAYER_SIGNATURE) ///< Locate DT_LAYER from service binding
-
-//------------------------------------------------------------------------------
-// Data
-//------------------------------------------------------------------------------
-
-extern DT_LAYER mEslLayer;
-
-//------------------------------------------------------------------------------
-// Socket Support Routines
-//------------------------------------------------------------------------------
-
-/**
- Allocate and initialize a DT_SOCKET structure.
-
- The ::SocketAllocate() function allocates a DT_SOCKET structure
- and installs a protocol on ChildHandle. If pChildHandle is a
- pointer to NULL, then a new handle is created and returned in
- pChildHandle. If pChildHandle is not a pointer to NULL, then
- the protocol installs on the existing pChildHandle.
-
- @param [in, out] pChildHandle Pointer to the handle of the child to create.
- If it is NULL, then a new handle is created.
- If it is a pointer to an existing UEFI handle,
- then the protocol is added to the existing UEFI
- handle.
- @param [in] DebugFlags Flags for debug messages
- @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.
-
- @retval EFI_SUCCESS The protocol was added to ChildHandle.
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
- the child
- @retval other The child handle was not created
-
-**/
-EFI_STATUS
-EFIAPI
-EslSocketAllocate (
- IN OUT EFI_HANDLE * pChildHandle,
- IN UINTN DebugFlags,
- IN OUT DT_SOCKET ** ppSocket
- );
-
-/**
- Allocate a packet for a receive or transmit operation
-
- @param [in] ppPacket Address to receive the DT_PACKET structure
- @param [in] LengthInBytes Length of the packet structure
- @param [in] DebugFlags Flags for debug messages
-
- @retval EFI_SUCCESS - The packet was allocated successfully
-
- **/
-EFI_STATUS
-EslSocketPacketAllocate (
- IN DT_PACKET ** ppPacket,
- IN size_t LengthInBytes,
- IN UINTN DebugFlags
- );
-
-/**
- Free a packet used for receive or transmit operation
-
- @param [in] pPacket Address of the DT_PACKET structure
- @param [in] DebugFlags Flags for debug messages
-
- @retval EFI_SUCCESS - The packet was allocated successfully
-
- **/
-EFI_STATUS
-EslSocketPacketFree (
- IN DT_PACKET * pPacket,
- IN UINTN DebugFlags
- );
-
-//------------------------------------------------------------------------------
-// Tcp4 Routines
-//------------------------------------------------------------------------------
+ union {
+ VOID * v; ///< VOID pointer
+ EFI_IP4_PROTOCOL * IPv4; ///< IP4 protocol pointer
+ EFI_TCP4_PROTOCOL * TCPv4; ///< TCP4 protocol pointer
+ EFI_UDP4_PROTOCOL * UDPv4; ///< UDP4 protocol pointer
+ } pProtocol; ///< Protocol structure address
+ union {
+ ESL_IP4_CONTEXT Ip4; ///< IPv4 management data
+ ESL_TCP4_CONTEXT Tcp4; ///< TCPv4 management data
+ ESL_UDP4_CONTEXT Udp4; ///< UDPv4 management data
+ } Context; ///< Network specific context
+}GCC_ESL_PORT;
/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
-
@param [in] pSocket Address of the socket structure.
@param [in] pSockAddr Address of a buffer to receive the remote
@@ -490,293 +389,276 @@ EslSocketPacketFree (
@retval Others Remote address not available
**/
+typedef
EFI_STATUS
-EslTcpAccept4 (
- IN DT_SOCKET * pSocket,
+(* PFN_API_ACCEPT) (
+ IN ESL_SOCKET * pSocket,
IN struct sockaddr * pSockAddr,
IN OUT socklen_t * pSockAddrLength
);
/**
- Bind a name to a socket.
-
- The ::TcpBind4 routine connects a name to A TCP4 stack on the local machine.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 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] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslTcpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- );
-
-/**
Poll for completion of the connection attempt.
- The ::TcpConnectPoll4 routine determines when the connection
- attempt transitions from being in process to being complete.
-
- @param [in] pSocket Address of the socket structure.
+ @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.
**/
+typedef
EFI_STATUS
-EslTcpConnectPoll4 (
- IN DT_SOCKET * pSocket
+(* PFN_API_CONNECT_POLL) (
+ IN ESL_SOCKET * pSocket
);
/**
- Connect to a remote system via the network.
+ Attempt to connect to a remote TCP port
- The ::TcpConnectStart4= routine starts the connection processing
- for a TCP4 port.
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCP network layer.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketConnect to initiate the TCP
+ network specific connect operations.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
@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.
**/
+typedef
EFI_STATUS
-EslTcpConnectStart4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+(* PFN_API_CONNECT_START) (
+ IN ESL_SOCKET * pSocket
);
/**
- Initialize the TCP4 service.
-
- This routine initializes the TCP4 service after its service binding
- protocol was located on a controller.
+ Get the local socket address
- @param [in] pService DT_SERVICE structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [out] pAddress Network address to receive the local system address
**/
-EFI_STATUS
-EFIAPI
-EslTcpInitialize4 (
- IN DT_SERVICE * pService
+typedef
+VOID
+(* PFN_API_LOCAL_ADDR_GET) (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
);
/**
- Get the local socket address
+ Set the local port address.
- @param [in] pSocket Address of the socket structure.
+ This routine sets the local port address.
- @param [out] pAddress Network address to receive the local system address
+ This support routine is called by ::EslSocketPortAllocate.
- @param [in,out] pAddressLength Length of the local network address structure
+ @param [in] ppPort Address of an ESL_PORT structure
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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 - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS The operation was successful
-**/
+ **/
+typedef
EFI_STATUS
-EslTcpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+(* PFN_API_LOCAL_ADDR_SET) (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
);
/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the remote system address
+ Determine if the socket is configured.
- @param [in,out] pAddressLength Length of the remote network address structure
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @param [in] pSocket Address of a ESL_SOCKET structure
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
-**/
-EFI_STATUS
-EslTcpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+ **/
+ typedef
+ EFI_STATUS
+ (* PFN_API_IS_CONFIGURED) (
+ IN ESL_SOCKET * pSocket
);
/**
Establish the known port to listen for network connections.
- The ::Tcp4Listen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::Tcp4Accept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
-
@param [in] pSocket Address of the socket structure.
-
+
@retval EFI_SUCCESS - Socket successfully created
@retval Other - Failed to enable the socket for listen
**/
+typedef
EFI_STATUS
-EslTcpListen4 (
- IN DT_SOCKET * pSocket
+(* PFN_API_LISTEN) (
+ 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.
+ Get the option value
- @param Event The listeen completion event
+ Retrieve the protocol options one at a time by name.
- @param pPort The DT_PORT structure address
-
-**/
-VOID
-EslTcpListenComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+ @param [in] pSocket Address of a ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [out] ppOptionData Buffer to receive address of option value
+ @param [out] pOptionLength Buffer to receive the option length
-/**
- Allocate and initialize a DT_PORT structure.
-
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle TCP4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Tcp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
-
- @retval EFI_SUCCESS - Socket successfully created
+ @retval EFI_SUCCESS - Socket data successfully received
**/
+typedef
EFI_STATUS
-EslTcpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 *pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+(* PFN_API_OPTION_GET) (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ OUT CONST void ** __restrict ppOptionData,
+ OUT socklen_t * __restrict pOptionLength
);
/**
- Close a TCP4 port.
+ Set the option value
- This routine releases the resources allocated by
- ::TcpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
+ Adjust the protocol options one at a time by name.
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
+ @param [in] pSocket Address of a ESL_SOCKET structure
+ @param [in] OptionName Name of the option
+ @param [in] pOptionValue Buffer containing the option value
+ @param [in] OptionLength Length of the buffer in bytes
-**/
+ @retval EFI_SUCCESS - Option successfully set
+
+ **/
+typedef
EFI_STATUS
-EslTcpPortClose4 (
- IN DT_PORT * pPort
+(* PFN_API_OPTION_SET) (
+ IN ESL_SOCKET * pSocket,
+ IN int OptionName,
+ IN CONST void * pOptionValue,
+ IN socklen_t OptionLength
);
/**
- Process the port close completion
+ Free a receive packet
+
+ This routine performs the network specific operations necessary
+ to free a receive packet.
- @param Event The close completion event
+ This routine is called by ::EslSocketPortCloseTxDone to free a
+ receive packet.
- @param pPort The DT_PORT structure address
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
+ @param [in, out] pRxBytes Address of the count of RX bytes
**/
+typedef
VOID
-EslTcpPortCloseComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
+(* PFN_API_PACKET_FREE) (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
);
/**
- Port close state 3
+ Initialize the network specific portions of an ::ESL_PORT structure.
- Continue the close operation after the receive is complete.
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
- @param [in] pPort Address of the port structure.
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the IPv4 protocol.
- @retval EFI_SUCCESS The port is closed
- @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.
+ @param [in] ppPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
-**/
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+typedef
EFI_STATUS
-EslTcpPortCloseRxDone4 (
- IN DT_PORT * pPort
+(* PFN_API_PORT_ALLOC) (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
);
/**
- Start the close operation on a TCP4 port.
+ Close a network specific port.
- @param [in] pPort Address of the port structure.
- @param [in] bAbort Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This routine releases the resources allocated by the
+ network specific PortAllocate routine.
+
+ This routine is called by ::EslSocketPortCloseRxDone as
+ the last step of closing processing.
+ 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
**/
+typedef
EFI_STATUS
-EslTcpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bAbort,
- IN UINTN DebugFlags
+(* PFN_API_PORT_CLOSE) (
+ IN ESL_PORT * pPort
);
/**
- Port close state 2
+ Perform the network specific close operation on the port.
- Continue the close operation after the transmission is complete.
+ This routine performs the network specific operation to
+ shutdown receive operations on the port.
- @param [in] pPort Address of the port structure.
+ 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.
**/
+typedef
EFI_STATUS
-EslTcpPortCloseTxDone4 (
- IN DT_PORT * pPort
+(* PFN_API_PORT_CLOSE_OP) (
+ IN ESL_PORT * pPort
);
/**
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.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pPacket Address of an ::ESL_PACKET structure.
- @param [in] Flags Message control flags
+ @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
@param [in] BufferLength Length of the the buffer
@@ -786,550 +668,850 @@ EslTcpPortCloseTxDone4 (
@param [out] pAddress Network address to receive the remote system address
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [out] pSkipBytes Address to receive the number of bytes skipped
- @retval EFI_SUCCESS - Socket data successfully received
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EslTcpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
+typedef
+UINT8 *
+(* PFN_API_RECEIVE) (
+ 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,
- IN OUT socklen_t * pAddressLength
+ OUT size_t * pSkipBytes
);
/**
- Cancel the receive operations
+ Get the remote socket address
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @param [in] pPort Address of an ::ESL_PORT structure.
- **/
-EFI_STATUS
-EslTcpRxCancel4 (
- IN DT_SOCKET * pSocket
+ @param [out] pAddress Network address to receive the remote system address
+
+**/
+typedef
+VOID
+(* PFN_API_REMOTE_ADDR_GET) (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
);
/**
- Process the receive completion
+ Set the remote address
- Buffer the data that was just received.
+ This routine sets the remote address in the port.
- @param Event The receive completion event
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- @param pPort The DT_PORT structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
-**/
-VOID
-EslTcpRxComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Start a receive operation
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pPort Address of the DT_PORT structure.
+ @retval EFI_SUCCESS The operation was successful
**/
-VOID
-EslTcpRxStart4 (
- IN DT_PORT * pPort
+typedef
+EFI_STATUS
+(* PFN_API_REMOTE_ADDR_SET) (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
);
/**
- Shutdown the TCP4 service.
+ Process the receive completion
+
+ This routine handles the receive completion event.
- This routine undoes the work performed by ::TcpInitialize4.
+ This routine is called by the low level network driver when
+ data is received.
- @param [in] pService DT_SERVICE structure address
+ @param [in] Event The receive completion event
+
+ @param [in] pIo The address of an ::ESL_IO_MGMT structure
**/
+typedef
VOID
-EFIAPI
-EslTcpShutdown4 (
- IN DT_SERVICE * pService
+(* PFN_API_RX_COMPLETE) (
+ IN EFI_EVENT Event,
+ IN ESL_IO_MGMT * pIo
);
/**
- Determine if the socket is configured.
+ Start a receive operation
+ This routine prepares a packet for the receive operation.
+ See the \ref ReceiveEngine section.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The port is connected
- @retval EFI_NOT_STARTED - The port is not connected
+ 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.
**/
- EFI_STATUS
- EslTcpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+typedef
+VOID
+(* PFN_API_RX_START) (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
);
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
- data for transmission. When necessary, this routine will
- start the transmit engine that performs the data transmission
- on the network connection.
+ @param [in] pSocket Address of a ESL_SOCKET structure
- @param [in] pSocket Address of a DT_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
- **/
+**/
+typedef
EFI_STATUS
-EslTcpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+(* PFN_API_TRANSMIT) (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
);
/**
- Process the normal data transmit completion
+ Process the transmit completion
+
+ This routine calls ::EslSocketTxComplete to handle the
+ transmit completion.
+
+ This routine is called by the network layers upon the completion
+ of a transmit operation.
- @param Event The normal transmit completion event
+ @param [in] Event The urgent transmit completion event
- @param pPort The DT_PORT structure address
+ @param [in] pIo The ESL_IO_MGMT structure address
**/
+typedef
VOID
-EslTcpTxComplete4 (
+(* PFN_API_TX_COMPLETE) (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
);
/**
- Process the urgent data transmit completion
+ Socket type control structure
+
+ This driver uses this structure to define the API for the socket type.
+**/
+typedef struct {
+ CONST CHAR8 * pName; ///< Protocol name
+ int DefaultProtocol; ///< Default protocol
+ UINTN ConfigDataOffset; ///< Offset in ::ESL_PORT to the configuration data
+ UINTN ServiceListOffset; ///< Offset in ::ESL_LAYER for the list of services
+ socklen_t MinimumAddressLength; ///< Minimum address length in bytes
+ socklen_t AddressLength; ///< Address length in bytes
+ sa_family_t AddressFamily; ///< Address family
+ UINTN RxPacketBytes; ///< Length of the RX packet allocation
+ UINTN RxZeroBytes; ///< Number of bytes to zero in RX packet
+ UINTN RxBufferOffset; ///< Offset of buffer address in ESL_IO_MGMT structure
+ BOOLEAN bOobSupported; ///< TRUE if out-of-band messages are supported
+ int BindTestErrno; ///< errno value if EslSocketBindTest fails
+ PFN_API_ACCEPT pfnAccept; ///< Accept a network connection
+ PFN_API_CONNECT_POLL pfnConnectPoll; ///< Poll for connection complete
+ PFN_API_CONNECT_START pfnConnectStart; ///< Start the connection to a remote system
+ PFN_API_IS_CONFIGURED pfnIsConfigured; ///< Determine if the socket is configured
+ PFN_API_LOCAL_ADDR_GET pfnLocalAddrGet; ///< Get the local address
+ PFN_API_LOCAL_ADDR_SET pfnLocalAddrSet; ///< Set the local address
+ PFN_API_LISTEN pfnListen; ///< Listen for connections on known server port
+ PFN_API_OPTION_GET pfnOptionGet; ///< Get the option value
+ PFN_API_OPTION_SET pfnOptionSet; ///< Set the option value
+ PFN_API_PACKET_FREE pfnPacketFree; ///< Free the receive packet
+ PFN_API_PORT_ALLOC pfnPortAllocate; ///< Allocate the network specific resources for the port
+ PFN_API_PORT_CLOSE pfnPortClose; ///< Close the network specific resources for the port
+ PFN_API_PORT_CLOSE_OP pfnPortCloseOp; ///< Perform the close operation on the port
+ BOOLEAN bPortCloseComplete; ///< TRUE = Close is complete after close operation
+ PFN_API_RECEIVE pfnReceive; ///< Attempt to receive some data
+ PFN_API_REMOTE_ADDR_GET pfnRemoteAddrGet; ///< Get remote address
+ PFN_API_REMOTE_ADDR_SET pfnRemoteAddrSet; ///< Set the remote system address
+ PFN_API_RX_COMPLETE pfnRxComplete; ///< RX completion
+ PFN_API_RX_START pfnRxStart; ///< Start a network specific receive operation
+ PFN_API_TRANSMIT pfnTransmit; ///< Attempt to buffer a packet for transmit
+ PFN_API_TX_COMPLETE pfnTxComplete; ///< TX completion for normal data
+ PFN_API_TX_COMPLETE pfnTxOobComplete; ///< TX completion for urgent data
+} ESL_PROTOCOL_API;
- @param Event The urgent transmit completion event
- @param pPort The DT_PORT structure address
+/**
+ Socket control structure
+ The driver uses this structure to manage the socket.
**/
-VOID
-EslTcpTxOobComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- );
+typedef struct _ESL_SOCKET {
+ UINTN Signature; ///< Structure identification
-/**
- Transmit data using a network connection.
+ //
+ // Protocol binding
+ //
+ EFI_SOCKET_PROTOCOL SocketProtocol; ///< Socket protocol declaration
+ CONST ESL_PROTOCOL_API * pApi; ///< API for the protocol
+ //
+ // Socket management
+ //
+ ESL_SOCKET * pNext; ///< Next socket in the list of sockets
+ int errno; ///< Error information for this socket
+ EFI_STATUS Status; ///< Asyncronous error information for this socket
+ SOCKET_STATE State; ///< Socket state
+ UINT32 DebugFlags; ///< Debug flags
- @param [in] pPort Address of a DT_PORT structure
- @param [in] pToken Address of either the OOB or normal transmit token
- @param [in] ppQueueHead Transmit queue head address
- @param [in] ppQueueTail Transmit queue tail address
- @param [in] ppPacket Active transmit packet address
+ //
+ // Socket options
+ //
+ BOOLEAN bListenCalled; ///< TRUE if listen was successfully called
+ BOOLEAN bOobInLine; ///< TRUE if out-of-band messages are to be received inline with normal data
+ BOOLEAN bIncludeHeader; ///< TRUE if including the IP header
- **/
-VOID
-EslTcpTxStart4 (
- IN DT_PORT * pPort,
- IN EFI_TCP4_IO_TOKEN * pToken,
- IN DT_PACKET ** ppQueueHead,
- IN DT_PACKET ** ppQueueTail,
- IN DT_PACKET ** ppPacket
- );
+ //
+ // Socket data
+ //
+ int Domain; ///< Specifies family of protocols
+ int Type; ///< Specifies how to make network connection
+ int Protocol; ///< Specifies lower layer protocol to use
+ BOOLEAN bConfigured; ///< Set after the socket is configured
-//------------------------------------------------------------------------------
-// Udp4 Routines
-//------------------------------------------------------------------------------
+ BOOLEAN bRxDisable; ///< Receive disabled via shutdown
+ size_t RxBytes; ///< Total Rx bytes
+ size_t RxOobBytes; ///< Urgent Rx bytes
+ EFI_STATUS RxError; ///< Error during receive
+
+ BOOLEAN bTxDisable; ///< Transmit disabled via shutdown
+ size_t TxBytes; ///< Normal Tx bytes
+ size_t TxOobBytes; ///< Urgent Tx bytes
+ EFI_STATUS TxError; ///< Error during transmit
+
+ //
+ // Pending connection data
+ //
+ BOOLEAN bConnected; ///< Set when connected, cleared by poll
+ EFI_STATUS ConnectStatus; ///< Connection status
+ UINTN MaxFifoDepth; ///< Maximum FIFO depth
+ UINTN FifoDepth; ///< Number of sockets in the FIFO
+ ESL_SOCKET * pFifoHead; ///< Head of the FIFO
+ ESL_SOCKET * pFifoTail; ///< Tail of the FIFO
+ ESL_SOCKET * pNextConnection; ///< Link in the FIFO
+
+ //
+ // Network use
+ //
+ ESL_PORT * pPortList; ///< List of ports managed by this socket
+ EFI_EVENT WaitAccept; ///< Wait for accept completion
+
+ //
+ // Receive data management
+ //
+ UINT32 MaxRxBuf; ///< Maximum size of the receive buffer
+ struct timeval RxTimeout; ///< Receive timeout
+ ESL_PACKET * pRxFree; ///< Free packet list
+ ESL_PACKET * pRxOobPacketListHead;///< Urgent data list head
+ ESL_PACKET * pRxOobPacketListTail;///< Urgent data list tail
+ ESL_PACKET * pRxPacketListHead; ///< Normal data list head
+ ESL_PACKET * pRxPacketListTail; ///< Normal data list tail
+
+ //
+ // Transmit data management
+ //
+ UINTN TxPacketOffset; ///< Offset for data pointer in ::ESL_PACKET
+ UINTN TxTokenEventOffset; ///< Offset to the Event in the TX token
+ UINTN TxTokenOffset; ///< Offset for data pointer in TX token
+ UINT32 MaxTxBuf; ///< Maximum size of the transmit buffer
+ ESL_PACKET * pTxOobPacketListHead;///< Urgent data list head
+ ESL_PACKET * pTxOobPacketListTail;///< Urgent data list tail
+ ESL_PACKET * pTxPacketListHead; ///< Normal data list head
+ ESL_PACKET * pTxPacketListTail; ///< Normal data list tail
+}GCC_ESL_SOCKET;
+
+#define SOCKET_FROM_PROTOCOL(a) CR (a, ESL_SOCKET, SocketProtocol, SOCKET_SIGNATURE) ///< Locate ESL_SOCKET from protocol
/**
- Bind a name to a socket.
+ Socket layer control structure
- The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.
+ The driver uses this structure to manage the driver.
+**/
+typedef struct {
+ UINTN Signature; ///< Structure identification
- @param [in] pSocket Address of the socket structure.
+ //
+ // Service binding interface
+ //
+ CONST EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding; ///< Driver's binding
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 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.
+ //
+ // Image data
+ //
+ EFI_HANDLE ImageHandle; ///< Image handle
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+ //
+ // Network services
+ //
+ ESL_SERVICE * pIp4List; ///< List of Ip4 services
+ ESL_SERVICE * pTcp4List; ///< List of Tcp4 services
+ ESL_SERVICE * pUdp4List; ///< List of Udp4 services
- @retval EFI_SUCCESS - Socket successfully created
+ //
+ // Socket management
+ //
+ ESL_SOCKET * pSocketList; ///< List of sockets
+} ESL_LAYER;
- **/
-EFI_STATUS
-EslUdpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- );
+#define LAYER_FROM_SERVICE(a) CR (a, ESL_LAYER, ServiceBinding, LAYER_SIGNATURE) ///< Locate ESL_LAYER from service binding
-/**
- Initialize the UDP4 service.
+//------------------------------------------------------------------------------
+// Data
+//------------------------------------------------------------------------------
+
+extern ESL_LAYER mEslLayer;
- This routine initializes the UDP4 service after its service binding
- protocol was located on a controller.
+extern CONST ESL_PROTOCOL_API cEslIp4Api;
+extern CONST ESL_PROTOCOL_API cEslTcp4Api;
+extern CONST ESL_PROTOCOL_API cEslUdp4Api;
- @param [in] pService DT_SERVICE structure address
+extern CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding;
+
+//------------------------------------------------------------------------------
+// Socket Support Routines
+//------------------------------------------------------------------------------
+
+/**
+ Allocate and initialize a ESL_SOCKET structure.
+
+ This support function allocates an ::ESL_SOCKET structure
+ and installs a protocol on ChildHandle. If pChildHandle is a
+ pointer to NULL, then a new handle is created and returned in
+ pChildHandle. If pChildHandle is not a pointer to NULL, then
+ the protocol installs on the existing pChildHandle.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [in, out] pChildHandle Pointer to the handle of the child to create.
+ If it is NULL, then a new handle is created.
+ If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI
+ handle.
+ @param [in] DebugFlags Flags for debug messages
+ @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child
+ @retval other The child handle was not created
+
**/
EFI_STATUS
EFIAPI
-EslUdpInitialize4 (
- IN DT_SERVICE * pService
+EslSocketAllocate (
+ IN OUT EFI_HANDLE * pChildHandle,
+ IN UINTN DebugFlags,
+ IN OUT ESL_SOCKET ** ppSocket
);
/**
- Allocate and initialize a DT_PORT structure.
+ Test the bind configuration.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle Udp4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Udp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ @param [in] pPort Address of the ::ESL_PORT structure.
+ @param [in] ErrnoValue errno value if test fails
- @retval EFI_SUCCESS - Socket successfully created
+ @retval EFI_SUCCESS The connection was successfully established.
+ @retval Others The connection attempt failed.
**/
EFI_STATUS
-EslUdpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslSocketBindTest (
+ IN ESL_PORT * pPort,
+ IN int ErrnoValue
);
/**
- Close a UDP4 port.
+ Copy a fragmented buffer into a destination buffer.
- This routine releases the resources allocated by
- ::UdpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
+ This support routine copies a fragmented buffer to the caller specified buffer.
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
+ This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
-**/
-EFI_STATUS
-EslUdpPortClose4 (
- IN DT_PORT * pPort
- );
+ @param [in] FragmentCount Number of fragments in the table
-/**
- Start the close operation on a UDP4 port, state 1.
+ @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ @param [in] BufferLength Length of the the buffer
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port has started the closing process
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ @param [in] pBuffer Address of a buffer to receive the data.
+
+ @param [in] pDataLength Number of received data bytes in the buffer.
+
+ @return Returns the address of the next free byte in the buffer.
**/
-EFI_STATUS
-EslUdpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+UINT8 *
+EslSocketCopyFragmentedBuffer (
+ IN UINT32 FragmentCount,
+ IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength
);
/**
- Port close state 2
+ Free the ESL_IO_MGMT event and structure
- Continue the close operation after the transmission is complete.
+ This support routine walks the free list to close the event in
+ the ESL_IO_MGMT structure and remove the structure from the free
+ list.
- @param [in] pPort Address of the port structure.
+ See the \ref TransmitEngine section.
- @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.
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+
+ @retval EFI_SUCCESS - The structures were properly initialized
**/
EFI_STATUS
-EslUdpPortCloseTxDone4 (
- IN DT_PORT * pPort
+EslSocketIoFree (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName
);
/**
- Connect to a remote system via the network.
+ Initialize the ESL_IO_MGMT structures
- The ::UdpConnectStart4= routine sets the remote address for the connection.
+ This support routine initializes the ESL_IO_MGMT structure and
+ places them on to a free list.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by the PortAllocate routines to prepare
+ the transmit engines. See the \ref TransmitEngine section.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
- @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.
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in, out] ppIo Address containing the first structure address. Upon
+ return this buffer contains the next structure address.
+ @param [in] TokenCount Number of structures to initialize
+ @param [in] ppFreeQueue Address of the free queue head
+ @param [in] DebugFlags Flags for debug messages
+ @param [in] pEventName Zero terminated string containing the event name
+ @param [in] pfnCompletion Completion routine address
- **/
+ @retval EFI_SUCCESS - The structures were properly initialized
+
+**/
EFI_STATUS
-EslUdpConnect4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+EslSocketIoInit (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT ** ppIo,
+ IN UINTN TokenCount,
+ IN ESL_IO_MGMT ** ppFreeQueue,
+ IN UINTN DebugFlags,
+ IN CHAR8 * pEventName,
+ IN EFI_EVENT_NOTIFY pfnCompletion
);
/**
- Get the local socket address
+ Determine if the socket is configured
- @param [in] pSocket Address of the socket structure.
+ This support routine is called to determine if the socket if the
+ configuration call was made to the network layer. The following
+ routines call this routine to verify that they may be successful
+ in their operations:
+ <ul>
+ <li>::EslSocketGetLocalAddress</li>
+ <li>::EslSocketGetPeerAddress</li>
+ <li>::EslSocketPoll</li>
+ <li>::EslSocketReceive</li>
+ <li>::EslSocketTransmit</li>
+ </ul>
- @param [out] pAddress Network address to receive the local system address
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
- @param [in,out] pAddressLength Length of the local network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS - The socket is configured
**/
EFI_STATUS
-EslUdpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketIsConfigured (
+ IN ESL_SOCKET * pSocket
);
/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
+ Allocate a packet for a receive or transmit operation
- @param [out] pAddress Network address to receive the remote system address
+ This support routine is called by ::EslSocketRxStart and the
+ network specific TxBuffer routines to get buffer space for the
+ next operation.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] ppPacket Address to receive the ::ESL_PACKET structure
+ @param [in] LengthInBytes Length of the packet structure
+ @param [in] ZeroBytes Length of packet to zero
+ @param [in] DebugFlags Flags for debug messages
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @retval EFI_SUCCESS - The packet was allocated successfully
-**/
+ **/
EFI_STATUS
-EslUdpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketPacketAllocate (
+ IN ESL_PACKET ** ppPacket,
+ IN size_t LengthInBytes,
+ IN size_t ZeroBytes,
+ IN UINTN DebugFlags
);
/**
- Receive data from a network connection.
-
- To minimize the number of buffer copies, the ::UdpRxComplete4
- routine queues the UDP4 driver's buffer to a list of datagrams
- waiting to be received. The socket driver holds on to the
- buffers from the UDP4 driver until the application layer requests
- the data or the socket is closed.
+ Free a packet used for receive or transmit operation
- The application calls this routine in the socket layer to
- receive datagrams from one or more remote systems. This routine
- removes the next available datagram from the list of datagrams
- and copies the data from the UDP4 driver's buffer into the
- application's buffer. The UDP4 driver's buffer is then returned.
+ This support routine is called by the network specific Close
+ and TxComplete routines and during error cases in RxComplete
+ and TxBuffer. Note that the network layers typically place
+ receive packets on the ESL_SOCKET::pRxFree list for reuse.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pPacket Address of an ::ESL_PACKET structure
+ @param [in] DebugFlags Flags for debug messages
- @param [in] Flags Message control flags
+ @retval EFI_SUCCESS - The packet was allocated successfully
- @param [in] BufferLength Length of the the buffer
+ **/
+EFI_STATUS
+EslSocketPacketFree (
+ IN ESL_PACKET * pPacket,
+ IN UINTN DebugFlags
+ );
- @param [in] pBuffer Address of a buffer to receive the data.
+/**
+ Allocate and initialize a ESL_PORT structure.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This routine initializes an ::ESL_PORT structure for use by
+ the socket. This routine calls a routine via
+ ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
+ specific resources. The resources are released later by the
+ \ref PortCloseStateMachine.
- @param [out] pAddress Network address to receive the remote system address
+ This support routine is called by ::EslSocketBind and
+ ::EslTcp4ListenComplete to connect the socket with the
+ underlying network adapter to the socket.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
+ @param [in] pService Address of an ::ESL_SERVICE structure.
+ @param [in] ChildHandle TCP4 child handle
+ @param [in] pSockAddr Address of a sockaddr structure that contains the
+ connection point on the local machine. An IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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 if EslSocketBindTest should be called
+ @param [in] DebugFlags Flags for debug messages
+ @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Socket successfully created
-**/
+ **/
EFI_STATUS
-EslUdpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+EslSocketPortAllocate (
+ IN ESL_SOCKET * pSocket,
+ IN ESL_SERVICE * pService,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest,
+ IN UINTN DebugFlags,
+ OUT ESL_PORT ** ppPort
);
/**
- Cancel the receive operations
-
- @param [in] pSocket Address of a DT_SOCKET structure
+ Close a port.
+
+ This routine releases the resources allocated by ::EslSocketPortAllocate.
+ This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
+ specific resources.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4PortAllocate - Port initialization failure</li>
+ <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
+ <li>::EslTcp4ConnectComplete - Connection failure and reducint the port list to a single port</li>
+ <li>::EslTcp4PortAllocate - Port initialization failure</li>
+ <li>::EslUdp4PortAllocate - Port initialization failure</li>
+ </ul>
+ See the \ref PortCloseStateMachine section.
- @retval EFI_SUCCESS - The cancel was successful
+ @param [in] pPort Address of an ::ESL_PORT structure.
- **/
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
+
+**/
EFI_STATUS
-EslUdpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslSocketPortClose (
+ IN ESL_PORT * pPort
);
/**
- Process the receive completion
+ Process the port close completion event
- Keep the UDP4 driver's buffer and append it to the list of
- datagrams for the application to receive. The UDP4 driver's
- buffer will be returned by either ::UdpReceive4 or
- ::UdpPortCloseTxDone4.
+ This routine attempts to complete the port close operation.
- @param Event The receive completion event
+ This routine is called by the TCP layer upon completion of
+ the close operation.
+ See the \ref PortCloseStateMachine section.
- @param pPort The DT_PORT structure address
+ @param [in] Event The close completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslUdpRxComplete4 (
+EslSocketPortCloseComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
);
/**
- Start a receive operation
+ Port close state 3
- @param [in] pPort Address of the DT_PORT structure.
+ This routine determines the state of the receive operations and
+ continues the close operation after the pending receive operations
+ are cancelled.
- **/
-VOID
-EslUdpRxStart4 (
- IN DT_PORT * pPort
+ This routine is called by
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslSocketPortCloseComplete</li>
+ <li>::EslSocketPortCloseTxDone</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
+ to determine the state of the receive operations.
+ See the \ref PortCloseStateMachine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @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
+EslSocketPortCloseRxDone (
+ IN ESL_PORT * pPort
);
/**
- Determine if the socket is configured.
+ Start the close operation on a port, state 1.
+ This routine marks the port as closed and initiates the \ref
+ PortCloseStateMachine. The first step is to allow the \ref
+ TransmitEngine to run down.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The port is connected
- @retval EFI_NOT_STARTED - The port is not connected
+ This routine is called by ::EslSocketCloseStart to initiate the socket
+ network specific close operation on the socket.
- **/
- EFI_STATUS
- EslUdpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] bCloseNow Set TRUE to abort active transfers
+ @param [in] DebugFlags Flags for debug messages
+
+ @retval EFI_SUCCESS The port is closed, not normally returned
+ @retval EFI_NOT_READY The port has started the closing process
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
+ most likely the routine was called already.
+
+**/
+EFI_STATUS
+EslSocketPortCloseStart (
+ IN ESL_PORT * pPort,
+ IN BOOLEAN bCloseNow,
+ IN UINTN DebugFlags
);
/**
- Process the transmit completion
+ Port close state 2
+
+ This routine determines the state of the transmit engine and
+ continue the close operation after the transmission is complete.
+ The next step is to stop the \ref ReceiveEngine.
+ See the \ref PortCloseStateMachine section.
+
+ This routine is called by ::EslSocketPortCloseStart to determine
+ if the transmission is complete.
- @param Event The normal transmit completion event
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param pPort The DT_PORT structure address
+ @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.
**/
-VOID
-EslUdpTxComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
+EFI_STATUS
+EslSocketPortCloseTxDone (
+ IN ESL_PORT * pPort
);
/**
- Shutdown the UDP4 service.
+ Cancel the receive operations
- This routine undoes the work performed by ::UdpInitialize4.
+ This routine cancels a pending receive operation.
+ See the \ref ReceiveEngine section.
- @param [in] pService DT_SERVICE structure address
+ This routine is called by ::EslSocketShutdown when the socket
+ layer is being shutdown.
-**/
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+
+ **/
VOID
-EFIAPI
-EslUdpShutdown4 (
- IN DT_SERVICE * pService
+EslSocketRxCancel (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
);
/**
- Buffer data for transmission over a network connection.
+ Process the receive completion
- This routine is called by the socket layer API 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 will start 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.
+ 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.
- Transmission errors are returned during the next transmission or
- during the close operation. Only buffering errors are returned
- during the current transmission attempt.
+ This routine is called when some data is received by:
+ <ul>
+ <li>::EslIp4RxComplete</li>
+ <li>::EslTcp4RxComplete</li>
+ <li>::EslUdp4RxComplete</li>
+ </ul>
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] Status Receive status
+ @param [in] LengthInBytes Length of the receive data
+ @param [in] bUrgent TRUE if urgent data is received and FALSE
+ for normal data.
- @param [in] Flags Message control flags
+**/
+VOID
+EslSocketRxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN EFI_STATUS Status,
+ IN UINTN LengthInBytes,
+ IN BOOLEAN bUrgent
+ );
- @param [in] BufferLength Length of the the buffer
+/**
+ Start a receive operation
- @param [in] pBuffer Address of a buffer to receive the data.
+ This routine posts a receive buffer to the network adapter.
+ See the \ref ReceiveEngine section.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This support routine is called by:
+ <ul>
+ <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
+ <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
+ <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
+ <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
+ </ul>
- @param [in] pAddress Network address of the remote system address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @param [in] AddressLength Length of the remote network address structure
+ **/
+VOID
+EslSocketRxStart (
+ IN ESL_PORT * pPort
+ );
- @retval EFI_SUCCESS - Socket data successfully buffered
+/**
+ Complete the transmit operation
+
+ This support routine handles the transmit completion processing for
+ the various network layers. It frees the ::ESL_IO_MGMT structure
+ and and frees packet resources by calling ::EslSocketPacketFree.
+ Transmit errors are logged in ESL_SOCKET::TxError.
+ See the \ref TransmitEngine section.
+
+ This routine is called by:
+ <ul>
+ <li>::EslIp4TxComplete</li>
+ <li>::EslTcp4TxComplete</li>
+ <li>::EslTcp4TxOobComplete</li>
+ <li>::EslUdp4TxComplete</li>
+ </ul>
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
+ @param [in] LengthInBytes Length of the data in bytes
+ @param [in] Status Transmit operation status
+ @param [in] pQueueType Zero terminated string describing queue type
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
-**/
-EFI_STATUS
-EslUdpTxBuffer4 (
- IN DT_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
+ **/
+VOID
+EslSocketTxComplete (
+ IN ESL_IO_MGMT * pIo,
+ IN UINT32 LengthInBytes,
+ IN EFI_STATUS Status,
+ IN CONST CHAR8 * pQueueType,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
);
/**
Transmit data using a network connection.
- @param [in] pPort Address of a DT_PORT structure
+ This support routine starts a transmit operation on the
+ underlying network layer.
+
+ The network specific code calls this routine to start a
+ transmit operation. See the \ref TransmitEngine section.
+
+ @param [in] pPort Address of an ::ESL_PORT structure
+ @param [in] ppQueueHead Transmit queue head address
+ @param [in] ppQueueTail Transmit queue tail address
+ @param [in] ppActive Active transmit queue address
+ @param [in] ppFree Free transmit queue address
**/
VOID
-EslUdpTxStart4 (
- IN DT_PORT * pPort
+EslSocketTxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_PACKET ** ppQueueHead,
+ IN ESL_PACKET ** ppQueueTail,
+ IN ESL_IO_MGMT ** ppActive,
+ IN ESL_IO_MGMT ** ppFree
);
//------------------------------------------------------------------------------
diff --git a/StdLib/EfiSocketLib/Tcp4.c b/StdLib/EfiSocketLib/Tcp4.c
index b489608a5b..ec03b96bc1 100644
--- a/StdLib/EfiSocketLib/Tcp4.c
+++ b/StdLib/EfiSocketLib/Tcp4.c
@@ -10,19 +10,88 @@
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 ::EslTcp4Listen 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 TCPv4 network layer calls
+ ::EslTcp4ListenComplete to complete the connection processing.
+ EslTcp4ListenComplete 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 ::EslTcp4Accept 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 TCPv4 network layer. It
+ configures the local TCPv4 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp4ConnectComplete routine gets called with the connection
+ status.
+
+ This routine is called by ::EslSocketConnect to initiate the TCPv4
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp4ConnectComplete.
+ This pair of routines walks through the list of local TCPv4
+ 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
+EslTcp4ConnectStart (
+ 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 TCPv4 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
+EslTcp4ListenComplete (
+ IN EFI_EVENT Event,
+ IN ESL_PORT * pPort
+ );
+
+
+/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
+ 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 TCPv4 protocol
+ specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
+ See the \ref ConnectionManagement section.
- @param [in] pSocket Address of the socket structure.
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
@param [in] pSockAddr Address of a buffer to receive the remote
network address.
@@ -36,15 +105,15 @@
**/
EFI_STATUS
-EslTcpAccept4 (
- IN DT_SOCKET * pSocket,
+EslTcp4Accept (
+ IN ESL_SOCKET * pSocket,
IN struct sockaddr * pSockAddr,
IN OUT socklen_t * pSockAddrLength
)
{
- DT_PORT * pPort;
+ ESL_PORT * pPort;
struct sockaddr_in * pRemoteAddress;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_TCP4_CONTEXT * pTcp4;
UINT32 RemoteAddress;
EFI_STATUS Status;
@@ -102,302 +171,37 @@ EslTcpAccept4 (
/**
- Bind a name to a socket.
-
- The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 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] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslTcpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- )
-{
- EFI_HANDLE ChildHandle;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pService;
- CONST struct sockaddr_in * pIp4Address;
- EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
- EFI_STATUS Status;
- EFI_STATUS TempStatus;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
-
- //
- // Validate the address length
- //
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
-
- //
- // Walk the list of services
- //
- pLayer = &mEslLayer;
- pService = pLayer->pTcp4List;
- while ( NULL != pService ) {
- //
- // Create the TCP port
- //
- pTcp4Service = pService->pInterface;
- ChildHandle = NULL;
- Status = pTcp4Service->CreateChild ( pTcp4Service,
- &ChildHandle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Tcp4 port handle created\r\n",
- ChildHandle ));
-
- //
- // Open the port
- //
- Status = EslTcpPortAllocate4 ( pSocket,
- pService,
- ChildHandle,
- (UINT8 *) &pIp4Address->sin_addr.s_addr,
- SwapBytes16 ( pIp4Address->sin_port ),
- DEBUG_BIND,
- &pPort );
- }
- else {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",
- Status ));
- ChildHandle = NULL;
- }
-
- //
- // Close the port if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
- TempStatus = pTcp4Service->DestroyChild ( pTcp4Service,
- ChildHandle );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Tcp4 port handle destroyed\r\n",
- ChildHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",
- ChildHandle,
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
- }
- }
-
- //
- // Set the next service
- //
- pService = pService->pNext;
- }
-
- //
- // Verify that at least one network connection was found
- //
- if ( NULL == pSocket->pPortList ) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
- "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
- ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
- pIp4Address->sin_addr.s_addr & 0xff,
- pIp4Address->sin_addr.s_addr ));
- pSocket->errno = EADDRNOTAVAIL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid TCP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Attempt to connect to a remote TCP port
-
- @param [in] pSocket Address of the 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
-EslTcpConnectAttempt4 (
- IN DT_SOCKET * pSocket
- )
-{
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
+ Process the remote connection completion event.
- DBG_ENTER ( );
-
- //
- // Determine if any more local adapters are available
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Configure the port
- //
- pTcp4 = &pPort->Context.Tcp4;
- pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
- pTcp4->ConfigData.TimeToLive = 255;
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Configure ( pTcp4Protocol,
- &pTcp4->ConfigData );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Failed to configure the Tcp4 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 ));
- pTcp4->bConfigured = TRUE;
-
- //
- // Attempt the connection to the remote system
- //
- Status = pTcp4Protocol->Connect ( pTcp4Protocol,
- &pTcp4->ConnectToken );
- if ( !EFI_ERROR ( Status )) {
- //
- // Connection in progress
- //
- pSocket->errno = EINPROGRESS;
- Status = EFI_NOT_READY;
- DEBUG (( DEBUG_CONNECT,
- "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
- pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
- pTcp4->ConfigData.AccessPoint.RemotePort ));
- }
- else {
- //
- // Connection error
- //
- pSocket->errno = EINVAL;
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Port 0x%08x not connected, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
- }
- else {
- //
- // No more local adapters available
- //
- pSocket->errno = ENETUNREACH;
- Status = EFI_NO_RESPONSE;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Process the remote connection attempt
-
- A connection attempt to a remote system has just completed when
- this routine is invoked. Release the port in the case of an
+ This routine handles the completion of a connection attempt. It
+ releases the port (TCPv4 adapter connection) in the case of an
error and start a connection attempt on the next port. If the
- connection attempt was successful, then release all of the other
- ports.
+ connection attempt was successful then this routine releases all
+ of the other ports.
- @param Event The connect completion event
+ This routine is called by the TCPv4 layer when a connect request
+ completes. It sets the ESL_SOCKET::bConnected flag to notify the
+ ::EslTcp4ConnectComplete 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 pPort The DT_PORT structure address
+ @param [in] Event The connect completion event
+
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslTcpConnectComplete4 (
+EslTcp4ConnectComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
)
{
BOOLEAN bRemoveFirstPort;
BOOLEAN bRemovePorts;
- DT_PORT * pNextPort;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PORT * pNextPort;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -422,10 +226,10 @@ EslTcpConnectComplete4 (
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
pTcp4->ConfigData.AccessPoint.RemotePort ));
//
@@ -440,17 +244,17 @@ EslTcpConnectComplete4 (
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
pPort,
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
pTcp4->ConfigData.AccessPoint.RemotePort,
Status ));
//
// Close the current port
//
- Status = EslTcpPortClose4 ( pPort );
+ Status = EslSocketPortClose ( pPort );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port closed\r\n",
@@ -466,7 +270,7 @@ EslTcpConnectComplete4 (
//
// Try to connect using the next port
//
- Status = EslTcpConnectAttempt4 ( pSocket );
+ Status = EslTcp4ConnectStart ( pSocket );
if ( EFI_NOT_READY != Status ) {
pSocket->ConnectStatus = Status;
bRemoveFirstPort = TRUE;
@@ -490,7 +294,7 @@ EslTcpConnectComplete4 (
//
while ( NULL != pPort ) {
pNextPort = pPort->pLinkSocket;
- EslTcpPortClose4 ( pPort );
+ EslSocketPortClose ( pPort );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_CONNECT,
"0x%08x: Port closed\r\n",
@@ -518,10 +322,16 @@ EslTcpConnectComplete4 (
/**
Poll for completion of the connection attempt.
- The ::TcpConnectPoll4 routine determines when the connection
- attempt transitions from being in process to being complete.
+ 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 ::EslTcp4ConnectComplete when the TCPv4 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 the socket structure.
+ @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.
@@ -529,8 +339,8 @@ EslTcpConnectComplete4 (
**/
EFI_STATUS
-EslTcpConnectPoll4 (
- IN DT_SOCKET * pSocket
+EslTcp4ConnectPoll (
+ IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status;
@@ -612,292 +422,165 @@ EslTcpConnectPoll4 (
/**
- Connect to a remote system via the network.
+ Attempt to connect to a remote TCP port
- The ::TcpConnectStart4= routine starts the connection processing
- for a TCP4 port.
+ This routine starts the connection processing for a SOCK_STREAM
+ or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
+ configures the local TCPv4 connection point and then attempts to
+ connect to a remote system. Upon completion, the
+ ::EslTcp4ConnectComplete routine gets called with the connection
+ status.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketConnect to initiate the TCPv4
+ network specific connect operations. The connection processing is
+ initiated by this routine and finished by ::EslTcp4ConnectComplete.
+ This pair of routines walks through the list of local TCPv4
+ connection points until a connection to the remote system is
+ made.
+
+ @param [in] pSocket Address of an ::ESL_SOCKET structure.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
-
@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
-EslTcpConnectStart4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+EslTcp4ConnectStart (
+ IN ESL_SOCKET * pSocket
)
{
- struct sockaddr_in LocalAddress;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- CONST struct sockaddr_in * pIp4Address;
+ ESL_PORT * pPort;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
DBG_ENTER ( );
-
+
//
- // Validate the address length
+ // Determine if any more local adapters are available
//
- Status = EFI_SUCCESS;
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
//
- // Determine if BIND was already called
+ // Configure the port
//
- if ( NULL == pSocket->pPortList ) {
- //
- // Allow any local port
- //
- ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
- LocalAddress.sin_len = sizeof ( LocalAddress );
- LocalAddress.sin_family = AF_INET;
- Status = EslSocketBind ( &pSocket->SocketProtocol,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len,
- &pSocket->errno );
+ pTcp4 = &pPort->Context.Tcp4;
+ pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
+ pTcp4->ConfigData.TimeToLive = 255;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
+ Status = pTcp4Protocol->Configure ( pTcp4Protocol,
+ &pTcp4->ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Failed to configure the Tcp4 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;
+ }
}
- if ( NULL != pSocket->pPortList ) {
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port configured\r\n",
+ pPort ));
+ pPort->bConfigured = TRUE;
+
//
- // Walk the list of ports
+ // Attempt the connection to the remote system
//
- pPort = pSocket->pPortList;
- while ( NULL != pPort ) {
+ Status = pTcp4Protocol->Connect ( pTcp4Protocol,
+ &pTcp4->ConnectToken );
+ if ( !EFI_ERROR ( Status )) {
//
- // Set the remote address
+ // Connection in progress
//
- pTcp4 = &pPort->Context.Tcp4;
- *(UINT32 *)&pTcp4->ConfigData.AccessPoint.RemoteAddress = pIp4Address->sin_addr.s_addr;
- pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pIp4Address->sin_port );
-
+ pSocket->errno = EINPROGRESS;
+ Status = EFI_NOT_READY;
+ DEBUG (( DEBUG_CONNECT,
+ "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp4->ConfigData.AccessPoint.RemotePort ));
+ }
+ else {
//
- // Set the next port
+ // Connection error
//
- pPort = pPort->pLinkSocket;
- }
-
- //
- // Attempt a connection using the first adapter
- //
- Status = EslTcpConnectAttempt4 ( pSocket );
- }
- }
- else {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid TCP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Initialize the TCP4 service.
-
- This routine initializes the TCP4 service after its service binding
- protocol was located on a controller.
-
- @param [in] pService DT_SERVICE structure address
-
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
-
-**/
-EFI_STATUS
-EFIAPI
-EslTcpInitialize4 (
- IN DT_SERVICE * pService
- )
-{
- DT_LAYER * pLayer;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Identify the service
- //
- pService->NetworkType = NETWORK_TYPE_TCP4;
-
- //
- // Connect this service to the service list
- //
- pLayer = &mEslLayer;
- pService->pNext = pLayer->pTcp4List;
- pLayer->pTcp4List = pService;
-
- //
- // Assume the list is empty
- //
- Status = EFI_SUCCESS;
-
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the local socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the local system address
+ 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;
- @param [in,out] pAddressLength Length of the local network address structure
+ case EFI_OUT_OF_RESOURCES:
+ pSocket->errno = ENOBUFS;
+ break;
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ case EFI_TIMEOUT:
+ pSocket->errno = ETIMEDOUT;
+ break;
-**/
-EFI_STATUS
-EslTcpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pLocalAddress;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
+ case EFI_NETWORK_UNREACHABLE:
+ pSocket->errno = ENETDOWN;
+ break;
- DBG_ENTER ( );
+ case EFI_HOST_UNREACHABLE:
+ pSocket->errno = EHOSTUNREACH;
+ break;
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
+ case EFI_PORT_UNREACHABLE:
+ case EFI_PROTOCOL_UNREACHABLE:
+ case EFI_CONNECTION_REFUSED:
+ pSocket->errno = ECONNREFUSED;
+ break;
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
- //
- // Verify the address length
- //
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pTcp4 = &pPort->Context.Tcp4;
- pLocalAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pLocalAddress, LengthInBytes );
- pLocalAddress->sin_family = AF_INET;
- pLocalAddress->sin_len = (uint8_t)LengthInBytes;
- pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
- CopyMem ( &pLocalAddress->sin_addr,
- &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
- sizeof ( pLocalAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
+ case EFI_CONNECTION_RESET:
+ pSocket->errno = ECONNRESET;
+ break;
+ }
+ }
}
}
else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the remote socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the remote system address
-
- @param [in,out] pAddressLength Length of the remote network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
-
-**/
-EFI_STATUS
-EslTcpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pRemoteAddress;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
//
- // Verify the address length
+ // No more local adapters available
//
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pTcp4 = &pPort->Context.Tcp4;
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pRemoteAddress, LengthInBytes );
- pRemoteAddress->sin_family = AF_INET;
- pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
- pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
- CopyMem ( &pRemoteAddress->sin_addr,
- &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
- sizeof ( pRemoteAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
+ pSocket->errno = ENETUNREACH;
+ Status = EFI_NO_RESPONSE;
}
-
+
//
// Return the operation status
//
@@ -909,27 +592,27 @@ EslTcpGetRemoteAddress4 (
/**
Establish the known port to listen for network connections.
- The ::Tcp4Listen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::Tcp4Accept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the listen routine is available online for reference.
+ 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 the socket structure.
+ @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
-EslTcpListen4 (
- IN DT_SOCKET * pSocket
+EslTcp4Listen (
+ IN ESL_SOCKET * pSocket
)
{
- DT_PORT * pNextPort;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PORT * pNextPort;
+ ESL_PORT * pPort;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
@@ -970,7 +653,7 @@ EslTcpListen4 (
pTcp4 = &pPort->Context.Tcp4;
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpListenComplete4,
+ (EFI_EVENT_NOTIFY)EslTcp4ListenComplete,
pPort,
&pTcp4->ListenToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
@@ -987,7 +670,7 @@ EslTcpListen4 (
//
// Configure the port
//
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
Status = pTcp4Protocol->Configure ( pTcp4Protocol,
&pTcp4->ConfigData );
if ( EFI_ERROR ( Status )) {
@@ -1025,7 +708,7 @@ EslTcpListen4 (
DEBUG (( DEBUG_LISTEN,
"0x%08x: Port configured\r\n",
pPort ));
- pTcp4->bConfigured = TRUE;
+ pPort->bConfigured = TRUE;
//
// Start the listen operation on the port
@@ -1078,9 +761,8 @@ EslTcpListen4 (
//
// Close the port upon error
//
- if ( EFI_ERROR ( Status ))
- {
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
+ if ( EFI_ERROR ( Status )) {
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
}
//
@@ -1132,30 +814,36 @@ EslTcpListen4 (
A system has initiated a connection attempt with a socket in the
listen state. Attempt to complete the connection.
- @param Event The listen completion event
+ The TCPv4 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 pPort The DT_PORT structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
**/
VOID
-EslTcpListenComplete4 (
+EslTcp4ListenComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_PORT * pPort
)
{
EFI_HANDLE ChildHandle;
+ struct sockaddr_in LocalAddress;
EFI_TCP4_CONFIG_DATA * pConfigData;
- DT_LAYER * pLayer;
- DT_PORT * pNewPort;
- DT_SOCKET * pNewSocket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_LAYER * pLayer;
+ ESL_PORT * pNewPort;
+ ESL_SOCKET * pNewSocket;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
EFI_HANDLE TcpPortHandle;
EFI_STATUS TempStatus;
DBG_ENTER ( );
+ VERIFY_AT_TPL ( TPL_SOCKETS );
//
// Assume success
@@ -1181,26 +869,36 @@ EslTcpListenComplete4 (
//
// Clone the socket parameters
//
+ pNewSocket->pApi = pSocket->pApi;
pNewSocket->Domain = pSocket->Domain;
pNewSocket->Protocol = pSocket->Protocol;
pNewSocket->Type = pSocket->Type;
//
- // Allocate a port for this connection
+ // Build the local address
//
pTcp4 = &pPort->Context.Tcp4;
- Status = EslTcpPortAllocate4 ( pNewSocket,
- pPort->pService,
- TcpPortHandle,
- &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
- 0,
- DEBUG_CONNECTION,
- &pNewPort );
+ LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_port = 0;
+ LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];
+
+ //
+ // 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
//
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
Status = pTcp4Protocol->Accept ( pTcp4Protocol,
&pTcp4->ListenToken );
@@ -1209,7 +907,6 @@ EslTcpListenComplete4 (
//
TcpPortHandle = NULL;
pTcp4 = &pNewPort->Context.Tcp4;
- pTcp4->bConfigured = TRUE;
//
// Check for an accept call error
@@ -1218,9 +915,10 @@ EslTcpListenComplete4 (
//
// Get the port configuration
//
+ pNewPort->bConfigured = TRUE;
pConfigData = &pTcp4->ConfigData;
pConfigData->ControlOption = &pTcp4->Option;
- pTcp4Protocol = pTcp4->pProtocol;
+ pTcp4Protocol = pNewPort->pProtocol.TCPv4;
Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,
NULL,
pConfigData,
@@ -1276,7 +974,7 @@ EslTcpListenComplete4 (
//
// Start the receive operation
//
- EslTcpRxStart4 ( pNewPort );
+ EslSocketRxStart ( pNewPort );
}
else {
DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
@@ -1297,7 +995,7 @@ EslTcpListenComplete4 (
//
// Close the listening port
//
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
}
}
@@ -1343,137 +1041,228 @@ EslTcpListenComplete4 (
/**
- Allocate and initialize a DT_PORT structure.
+ Get the local socket address.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle TCP4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Tcp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ This routine returns the IPv4 address and TCP port number associated
+ with the local socket.
- @retval EFI_SUCCESS - Socket successfully created
+ 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
+EslTcp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
+ )
+{
+ struct sockaddr_in * pLocalAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
+
+ DBG_ENTER ( );
+
+ //
+ // Return the local address
+ //
+ pTcp4 = &pPort->Context.Tcp4;
+ pLocalAddress = (struct sockaddr_in *)pSockAddr;
+ pLocalAddress->sin_family = AF_INET;
+ pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_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 IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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
-EslTcpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslTcp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
)
{
- UINTN LengthInBytes;
EFI_TCP4_ACCESS_POINT * pAccessPoint;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Use for/break instead of goto
- for ( ; ; ) {
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
//
- // Allocate a port structure
+ // The local address must not be the broadcast address
//
- pLayer = &mEslLayer;
- LengthInBytes = sizeof ( *pPort );
- Status = gBS->AllocatePool ( EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **)&pPort );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to allocate the port structure, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- pPort = NULL;
- break;
- }
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "0x%08x: Allocate pPort, %d bytes\r\n",
- pPort,
- LengthInBytes ));
-
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
//
- // Initialize the port
+ // Set the local address
//
- ZeroMem ( pPort, LengthInBytes );
- pPort->Signature = PORT_SIGNATURE;
- pPort->pService = pService;
- pPort->pSocket = pSocket;
- pPort->pfnCloseStart = EslTcpPortCloseStart4;
- pPort->DebugFlags = DebugFlags;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
+ pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];
+ pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];
+ pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];
+ pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];
//
- // Allocate the receive event
+ // Determine if the default address is used
//
- pTcp4 = &pPort->Context.Tcp4;
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpRxComplete4,
- pPort,
- &pTcp4->RxToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the receive event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_RX | DEBUG_POOL,
- "0x%08x: Created receive event\r\n",
- pTcp4->RxToken.CompletionToken.Event ));
-
+ pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
//
- // Allocate the urgent transmit event
+ // Set the subnet mask
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpTxOobComplete4,
- pPort,
- &pTcp4->TxOobToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
+ if ( pAccessPoint->UseDefaultAddress ) {
+ pAccessPoint->SubnetMask.Addr[0] = 0;
+ pAccessPoint->SubnetMask.Addr[1] = 0;
+ pAccessPoint->SubnetMask.Addr[2] = 0;
+ pAccessPoint->SubnetMask.Addr[3] = 0;
+ }
+ else {
+ pAccessPoint->SubnetMask.Addr[0] = 0xff;
+ pAccessPoint->SubnetMask.Addr[1] = 0xff;
+ pAccessPoint->SubnetMask.Addr[2] = 0xff;
+ pAccessPoint->SubnetMask.Addr[3] = 0xff;
}
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created urgent transmit event\r\n",
- pTcp4->TxOobToken.CompletionToken.Event ));
//
- // Allocate the normal transmit event
+ // Validate the IP address
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpTxComplete4,
- pPort,
- &pTcp4->TxToken.CompletionToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the normal transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
+ pAccessPoint->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Set the port number
+ //
+ pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );
+
+ //
+ // Display the local address
+ //
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pAccessPoint->StationAddress.Addr[0],
+ pAccessPoint->StationAddress.Addr[1],
+ pAccessPoint->StationAddress.Addr[2],
+ pAccessPoint->StationAddress.Addr[3],
+ pAccessPoint->StationPort ));
}
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created normal transmit event\r\n",
- pTcp4->TxToken.CompletionToken.Event ));
+ }
+
+ //
+ // 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
+EslTcp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
+ )
+{
+ DBG_ENTER ( );
+ //
+ // Account for the receive bytes
+ //
+ *pRxBytes -= pPacket->Op.Tcp4Rx.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 TCPv4 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
+EslTcp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
+ )
+{
+ EFI_TCP4_ACCESS_POINT * pAccessPoint;
+ ESL_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Use for/break instead of goto
+ for ( ; ; ) {
//
// Allocate the close event
//
+ pSocket = pPort->pSocket;
+ pTcp4 = &pPort->Context.Tcp4;
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpPortCloseComplete4,
+ (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
pPort,
&pTcp4->CloseToken.CompletionToken.Event);
if ( EFI_ERROR ( Status )) {
@@ -1492,7 +1281,7 @@ EslTcpPortAllocate4 (
//
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,
+ (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,
pPort,
&pTcp4->ConnectToken.CompletionToken.Event);
if ( EFI_ERROR ( Status )) {
@@ -1507,90 +1296,30 @@ EslTcpPortAllocate4 (
pTcp4->ConnectToken.CompletionToken.Event ));
//
- // Open the port protocol
- //
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiTcp4ProtocolGuid,
- (VOID **) &pTcp4->pProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",
- pTcp4->Handle ));
- pSocket->errno = EEXIST;
- break;
- }
- DEBUG (( DebugFlags,
- "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",
- pTcp4->pProtocol,
- ChildHandle ));
-
- //
- // Set the port address
- //
- pTcp4->Handle = ChildHandle;
- pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
- pAccessPoint->StationPort = PortNumber;
- if (( 0 == pIpAddress[0])
- && ( 0 == pIpAddress[1])
- && ( 0 == pIpAddress[2])
- && ( 0 == pIpAddress[3])) {
- pAccessPoint->UseDefaultAddress = TRUE;
- }
- else {
- pAccessPoint->StationAddress.Addr[0] = pIpAddress[0];
- pAccessPoint->StationAddress.Addr[1] = pIpAddress[1];
- pAccessPoint->StationAddress.Addr[2] = pIpAddress[2];
- pAccessPoint->StationAddress.Addr[3] = pIpAddress[3];
- pAccessPoint->SubnetMask.Addr[0] = 0xff;
- pAccessPoint->SubnetMask.Addr[1] = 0xff;
- pAccessPoint->SubnetMask.Addr[2] = 0xff;
- pAccessPoint->SubnetMask.Addr[3] = 0xff;
- }
- pAccessPoint->ActiveFlag = FALSE;
- pTcp4->ConfigData.TimeToLive = 255;
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Add this port to the socket
+ // Initialize the port
//
- pPort->pLinkSocket = pSocket->pPortList;
- pSocket->pPortList = pPort;
- DEBUG (( DebugFlags,
- "0x%08x: Socket adding port: 0x%08x\r\n",
- pSocket,
- pPort ));
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );
//
- // Add this port to the service
+ // Save the cancel, receive and transmit addresses
+ // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
//
- pPort->pLinkService = pService->pPortList;
- pService->pPortList = pPort;
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;
//
- // Return the port
+ // Set the configuration flags
//
- *ppPort = pPort;
+ pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
+ pAccessPoint->ActiveFlag = FALSE;
+ pTcp4->ConfigData.TimeToLive = 255;
break;
}
//
- // Clean up after the error if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {
- //
- // Close the port
- //
- EslTcpPortClose4 ( pPort );
- }
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -1601,127 +1330,35 @@ EslTcpPortAllocate4 (
/**
Close a TCP4 port.
- This routine releases the resources allocated by
- ::TcpPortAllocate4().
+ This routine releases the network specific resources allocated by
+ ::EslTcp4PortAllocate.
+
+ This routine is called by ::EslSocketPortClose.
+ See the \ref PortCloseStateMachine section.
- @param [in] pPort Address of the port structure.
+ @param [in] pPort Address of an ::ESL_PORT structure.
@retval EFI_SUCCESS The port is closed
@retval other Port close error
**/
EFI_STATUS
-EslTcpPortClose4 (
- IN DT_PORT * pPort
+EslTcp4PortClose (
+ IN ESL_PORT * pPort
)
{
UINTN DebugFlags;
- DT_LAYER * pLayer;
- DT_PACKET * pPacket;
- DT_PORT * pPreviousPort;
- DT_SERVICE * pService;
- DT_SOCKET * pSocket;
- EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
// Locate the port in the socket list
//
Status = EFI_SUCCESS;
- pLayer = &mEslLayer;
DebugFlags = pPort->DebugFlags;
- pSocket = pPort->pSocket;
- pPreviousPort = pSocket->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the socket list
- //
- pSocket->pPortList = pPort->pLinkSocket;
- }
- else {
- //
- // Locate the port in the middle of the socket list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkSocket != pPort )) {
- pPreviousPort = pPreviousPort->pLinkSocket;
- }
- if ( NULL != pPreviousPort ) {
- //
- // Remove the port from the middle of the socket list
- //
- pPreviousPort->pLinkSocket = pPort->pLinkSocket;
- }
- }
-
- //
- // Locate the port in the service list
- //
- pService = pPort->pService;
- pPreviousPort = pService->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the service list
- //
- pService->pPortList = pPort->pLinkService;
- }
- else {
- //
- // Locate the port in the middle of the service list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkService != pPort )) {
- pPreviousPort = pPreviousPort->pLinkService;
- }
- if ( NULL != pPreviousPort ) {
- //
- // Remove the port from the middle of the service list
- //
- pPreviousPort->pLinkService = pPort->pLinkService;
- }
- }
-
- //
- // Empty the urgent receive queue
- //
pTcp4 = &pPort->Context.Tcp4;
- while ( NULL != pSocket->pRxOobPacketListHead ) {
- pPacket = pSocket->pRxOobPacketListHead;
- pSocket->pRxOobPacketListHead = pPacket->pNext;
- pSocket->RxOobBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxOobPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxOobBytes );
-
- //
- // Empty the receive queue
- //
- while ( NULL != pSocket->pRxPacketListHead ) {
- pPacket = pSocket->pRxPacketListHead;
- pSocket->pRxPacketListHead = pPacket->pNext;
- pSocket->RxBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Empty the receive free queue
- //
- while ( NULL != pSocket->pRxFree ) {
- pPacket = pSocket->pRxFree;
- pSocket->pRxFree = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
//
// Done with the connect event
@@ -1778,121 +1415,6 @@ EslTcpPortClose4 (
}
//
- // Done with the receive event
- //
- if ( NULL != pTcp4->RxToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->RxToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed receive event\r\n",
- pTcp4->RxToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the receive event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the normal transmit event
- //
- if ( NULL != pTcp4->TxToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->TxToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed normal transmit event\r\n",
- pTcp4->TxToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the urgent transmit event
- //
- if ( NULL != pTcp4->TxOobToken.CompletionToken.Event ) {
- Status = gBS->CloseEvent ( pTcp4->TxOobToken.CompletionToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed urgent transmit event\r\n",
- pTcp4->TxOobToken.CompletionToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the TCP protocol
- //
- pTcp4Service = pService->pInterface;
- if ( NULL != pTcp4->pProtocol ) {
- Status = gBS->CloseProtocol ( pTcp4->Handle,
- &gEfiTcp4ProtocolGuid,
- pLayer->ImageHandle,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags,
- "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",
- pTcp4->pProtocol,
- pTcp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
- pTcp4->Handle,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the TCP port
- //
- if ( NULL != pTcp4->Handle ) {
- Status = pTcp4Service->DestroyChild ( pTcp4Service,
- pTcp4->Handle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Tcp4 port handle destroyed\r\n",
- pTcp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Release the port structure
- //
- Status = gBS->FreePool ( pPort );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Free pPort, %d bytes\r\n",
- pPort,
- sizeof ( *pPort )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
-
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -1901,94 +1423,52 @@ EslTcpPortClose4 (
/**
- Process the port close completion
-
- @param Event The close completion event
-
- @param pPort The DT_PORT structure address
-
-**/
-VOID
-EslTcpPortCloseComplete4 (
- IN EFI_EVENT Event,
- IN DT_PORT * pPort
- )
-{
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
-
- //
- // Release the resources once the receive operation completes
- //
- Status = EslTcpPortCloseRxDone4 ( pPort );
- DBG_EXIT_STATUS ( Status );
-}
+ Perform the network specific close operation on the port.
+ This routine performs a cancel operations on the TCPv4 port to
+ shutdown the receive operations on the port.
-/**
- Start the close operation on a TCP4 port, state 1.
+ This routine is called by the ::EslSocketPortCloseTxDone
+ routine after the port completes all of the transmission.
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ @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 has started the closing process
+ @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
-EslTcpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+EslTcp4PortCloseOp (
+ IN ESL_PORT * pPort
)
{
- DT_SOCKET * pSocket;
+ ESL_TCP4_CONTEXT * pTcp4;
+ EFI_TCP4_PROTOCOL * pTcp4Protocol;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Mark the port as closing
+ // Close the configured port
//
- Status = EFI_ALREADY_STARTED;
- pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_STARTED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
+ Status = EFI_SUCCESS;
+ pTcp4 = &pPort->Context.Tcp4;
+ pTcp4Protocol = pPort->pProtocol.TCPv4;
+ pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;
+ Status = pTcp4Protocol->Close ( pTcp4Protocol,
+ &pTcp4->CloseToken );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port close started\r\n",
pPort ));
- pPort->bCloseNow = bCloseNow;
- pPort->DebugFlags = DebugFlags;
-
- //
- // Determine if transmits are complete
- //
- Status = EslTcpPortCloseTxDone4 ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
+ pPort,
+ Status ));
}
//
@@ -2000,562 +1480,224 @@ EslTcpPortCloseStart4 (
/**
- Port close state 3
+ Receive data from a network connection.
- Continue the close operation after the receive is complete.
+ 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.
- @param [in] pPort Address of the port structure.
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
+ sockets.
- @retval EFI_SUCCESS The port is closed
- @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.
+ @param [in] pPort Address of an ::ESL_PORT structure.
-**/
-EFI_STATUS
-EslTcpPortCloseRxDone4 (
- IN DT_PORT * pPort
+ @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 *
+EslTcp4Receive (
+ 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
)
{
- PORT_STATE PortState;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_STATUS Status;
+ size_t DataLength;
+ struct sockaddr_in * pRemoteAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that the port is closing
+ // Return the remote system address if requested
//
- Status = EFI_ALREADY_STARTED;
- PortState = pPort->State;
- if (( PORT_STATE_CLOSE_TX_DONE == PortState )
- || ( PORT_STATE_CLOSE_DONE == PortState )) {
+ if ( NULL != pAddress ) {
//
- // Determine if the receive operation is pending
+ // Build the remote address
//
- Status = EFI_NOT_READY;
pTcp4 = &pPort->Context.Tcp4;
- if ( NULL == pTcp4->pReceivePending ) {
- //
- // The receive operation is complete
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_RX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
- pPort ));
-
- //
- // Determine if the close operation has completed
- //
- if ( PORT_STATE_CLOSE_DONE == PortState ) {
- //
- // The close operation has completed
- // Release the port resources
- //
- Status = EslTcpPortClose4 ( pPort );
- }
- else
- {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Close operation still pending!\r\n",
- pPort ));
- }
- }
- else {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Receive still pending!\r\n",
- pPort ));
- }
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
+ pTcp4->ConfigData.AccessPoint.RemotePort ));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
}
//
- // Return the operation status
+ // Determine the amount of received data
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Port close state 2
-
- Continue the close operation after the transmission is complete.
-
- @param [in] pPort Address of the 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
-EslTcpPortCloseTxDone4 (
- IN DT_PORT * pPort
- )
-{
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ DataLength = pPacket->ValidBytes;
+ if ( BufferLength < DataLength ) {
+ DataLength = BufferLength;
+ }
//
- // Verify the socket layer synchronization
+ // Move the data into the buffer
//
- VERIFY_TPL ( TPL_SOCKETS );
+ 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 );
//
- // All transmissions are complete or must be stopped
- // Mark the port as TX complete
+ // Determine if the data is being read
//
- Status = EFI_ALREADY_STARTED;
- if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
+ if ( *pbConsumePacket ) {
//
- // Verify that the transmissions are complete
+ // Account for the bytes consumed
//
- pSocket = pPort->pSocket;
- if ( pPort->bCloseNow
- || ( EFI_SUCCESS != pSocket->TxError )
- || (( 0 == pSocket->TxOobBytes )
- && ( 0 == pSocket->TxBytes ))) {
- //
- // Start the close operation on the port
- //
- pTcp4 = &pPort->Context.Tcp4;
- pTcp4->CloseToken.AbortOnClose = FALSE;
- pTcp4Protocol = pTcp4->pProtocol;
- if ( !pTcp4->bConfigured ) {
- //
- // Skip the close operation since the port is not
- // configured
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
- pPort ));
- Status = EFI_SUCCESS;
- }
- else {
- //
- // Close the configured port
- //
- Status = pTcp4Protocol->Close ( pTcp4Protocol,
- &pTcp4->CloseToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port close started\r\n",
- pPort ));
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_TX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\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 ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
+ 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 )) {
//
- // Determine if the receive operation is pending
+ // All done with this packet
+ // Account for any discarded data
//
- if ( !EFI_ERROR ( Status )) {
- Status = EslTcpPortCloseRxDone4 ( pPort );
- }
+ *pSkipBytes = pPacket->ValidBytes;
}
- else {
+ else
+ {
//
- // Transmissions are still active, exit
+ // More data to consume later
//
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Transmits are still pending!\r\n",
- pPort ));
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
+ *pbConsumePacket = FALSE;
}
}
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = DataLength;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
- Receive data from a network connection.
-
+ Get the remote socket address.
- @param [in] pSocket Address of a DT_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.
+ This routine returns the address of the remote connection point
+ associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
- @param [out] pAddress Network address to receive the remote system address
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the TCPv4 address and por number associated with the network adapter.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS - Socket data successfully received
+ @param [out] pAddress Network address to receive the remote system address
- **/
-EFI_STATUS
-EslTcpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+**/
+VOID
+EslTcp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
)
{
- socklen_t AddressLength;
- size_t BytesToCopy;
- in_addr_t IpAddress;
- size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_PACKET ** ppQueueHead;
- DT_PACKET ** ppQueueTail;
struct sockaddr_in * pRemoteAddress;
- size_t * pRxDataBytes;
- DT_TCP4_CONTEXT * pTcp4;
- struct sockaddr_in RemoteAddress;
- EFI_STATUS Status;
+ ESL_TCP4_CONTEXT * pTcp4;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_UNSUPPORTED;
- pSocket->errno = ENOTCONN;
-
- //
- // Verify that the socket is connected
+ // Return the remote address
//
- if (( SOCKET_STATE_CONNECTED == pSocket->State )
- || ( PORT_STATE_RX_ERROR == pSocket->State )) {
- //
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine the queue head
- //
- pTcp4 = &pPort->Context.Tcp4;
- if ( 0 != ( Flags & MSG_OOB )) {
- ppQueueHead = &pSocket->pRxOobPacketListHead;
- ppQueueTail = &pSocket->pRxOobPacketListTail;
- pRxDataBytes = &pSocket->RxOobBytes;
- }
- else {
- ppQueueHead = &pSocket->pRxPacketListHead;
- ppQueueTail = &pSocket->pRxPacketListTail;
- pRxDataBytes = &pSocket->RxBytes;
- }
-
- //
- // Determine if there is any data on the queue
- //
- pPacket = *ppQueueHead;
- if ( NULL != pPacket ) {
- //
- // Validate the return address parameters
- //
- if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
- //
- // Return the remote system address if requested
- //
- if ( NULL != pAddress ) {
- //
- // Build the remote address
- //
- ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
- RemoteAddress.sin_len = sizeof ( RemoteAddress );
- RemoteAddress.sin_family = AF_INET;
- IpAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
- IpAddress <<= 8;
- IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
- RemoteAddress.sin_addr.s_addr = IpAddress;
- RemoteAddress.sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
-
- //
- // Copy the address
- //
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- AddressLength = sizeof ( *pRemoteAddress );
- if ( AddressLength > *pAddressLength ) {
- AddressLength = *pAddressLength;
- }
- CopyMem ( pRemoteAddress,
- &RemoteAddress,
- AddressLength );
-
- //
- // Update the address length
- //
- *pAddressLength = AddressLength;
- }
-
- //
- // Copy the received data
- //
- LengthInBytes = 0;
- do {
- //
- // Determine the amount of received data
- //
- BytesToCopy = pPacket->Op.Tcp4Rx.ValidBytes;
- if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
- BytesToCopy = BufferLength - LengthInBytes;
- }
- LengthInBytes += BytesToCopy;
-
- //
- // 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,
- BytesToCopy ));
- CopyMem ( pBuffer, pPacket->Op.Tcp4Rx.pBuffer, BytesToCopy );
-
- //
- // Determine if the data is being read
- //
- if ( 0 == ( Flags & MSG_PEEK )) {
- //
- // Account for the bytes consumed
- //
- pPacket->Op.Tcp4Rx.pBuffer += BytesToCopy;
- pPacket->Op.Tcp4Rx.ValidBytes -= BytesToCopy;
- *pRxDataBytes -= BytesToCopy;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port account for 0x%08x bytes\r\n",
- pPort,
- BytesToCopy ));
-
- //
- // Determine if the entire packet was consumed
- //
- if (( 0 == pPacket->Op.Tcp4Rx.ValidBytes )
- || ( SOCK_STREAM != pSocket->Type )) {
- //
- // All done with this packet
- // Account for any discarded data
- //
- *pRxDataBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
- if ( 0 != pPacket->Op.Tcp4Rx.ValidBytes ) {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
- pPort,
- pPacket->Op.Tcp4Rx.ValidBytes ));
- }
-
- //
- // Remove this packet from the queue
- //
- *ppQueueHead = pPacket->pNext;
- if ( NULL == *ppQueueHead ) {
- *ppQueueTail = NULL;
- }
-
- //
- // Move the packet to the free queue
- //
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port freeing packet 0x%08x\r\n",
- pPort,
- pPacket ));
-
- //
- // Restart this receive operation if necessary
- //
- if (( NULL == pTcp4->pReceivePending )
- && ( MAX_RX_DATA > pSocket->RxBytes )) {
- EslTcpRxStart4 ( pPort );
- }
- }
- }
-
- //
- // Get the next packet
- //
- pPacket = *ppQueueHead;
- } while (( SOCK_STREAM == pSocket->Type )
- && ( NULL != pPacket )
- && ( 0 == ( Flags & MSG_PEEK ))
- && ( BufferLength > LengthInBytes ));
+ pTcp4 = &pPort->Context.Tcp4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
- //
- // Return the data length
- //
- *pDataLength = LengthInBytes;
+ DBG_EXIT ( );
+}
- //
- // Successful operation
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
- }
- else {
- //
- // Bad return address pointer and length
- //
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- }
- else {
- //
- // The queue is empty
- // Determine if it is time to return the receive error
- //
- if ( EFI_ERROR ( pSocket->RxError )
- && ( NULL == pSocket->pRxPacketListHead )
- && ( NULL == pSocket->pRxOobPacketListHead )) {
- Status = pSocket->RxError;
- pSocket->RxError = EFI_SUCCESS;
- switch ( Status ) {
- default:
- pSocket->errno = EIO;
- break;
-
- case EFI_CONNECTION_FIN:
- //
- // Continue to return zero bytes received when the
- // peer has successfully closed the connection
- //
- pSocket->RxError = EFI_CONNECTION_FIN;
- *pDataLength = 0;
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- break;
- case EFI_CONNECTION_REFUSED:
- pSocket->errno = ECONNREFUSED;
- break;
+/**
+ Set the remote address
- case EFI_CONNECTION_RESET:
- pSocket->errno = ECONNRESET;
- break;
+ This routine sets the remote address in the port.
- case EFI_HOST_UNREACHABLE:
- pSocket->errno = EHOSTUNREACH;
- break;
-
- case EFI_NETWORK_UNREACHABLE:
- pSocket->errno = ENETUNREACH;
- break;
-
- case EFI_PORT_UNREACHABLE:
- pSocket->errno = EPROTONOSUPPORT;
- break;
-
- case EFI_PROTOCOL_UNREACHABLE:
- pSocket->errno = ENOPROTOOPT;
- break;
- }
- }
- else {
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
- }
- }
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Cancel the receive operations
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslTcpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslTcp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
)
{
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
+ CONST struct sockaddr_in * pRemoteAddress;
+ ESL_TCP4_CONTEXT * pTcp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_NOT_FOUND;
-
+ // Set the remote address
//
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if a receive is pending
- //
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pReceivePending;
- if ( NULL != pPacket ) {
- //
- // Attempt to cancel the receive operation
- //
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Cancel ( pTcp4Protocol,
- &pTcp4->RxToken.CompletionToken );
- if ( EFI_NOT_FOUND == Status ) {
- //
- // The receive is complete
- //
- Status = EFI_SUCCESS;
- }
- }
+ pTcp4 = &pPort->Context.Tcp4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
+ Status = EFI_SUCCESS;
+ if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid remote address\r\n" ));
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EAFNOSUPPORT;
}
//
@@ -2569,321 +1711,107 @@ EslTcpRxCancel4 (
/**
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 TCPv4 driver when some data is
+ received.
+
Buffer the data that was just received.
- @param Event The receive completion event
+ @param [in] Event The receive completion event
- @param pPort The DT_PORT structure address
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
**/
VOID
-EslTcpRxComplete4 (
+EslTcp4RxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
BOOLEAN bUrgent;
size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PACKET * pPrevious;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PACKET * pPacket;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Mark this receive complete
+ // Get the operation status.
//
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pReceivePending;
- pTcp4->pReceivePending = NULL;
+ Status = pIo->Token.Tcp4Rx.CompletionToken.Status;
//
- // Determine if this receive was successful
+ // +--------------------+ +---------------------------+
+ // | ESL_IO_MGMT | | ESL_PACKET |
+ // | | | |
+ // | +---------------+ +-----------------------+ |
+ // | | Token | | EFI_TCP4_RECEIVE_DATA | |
+ // | | RxData --> | | |
+ // | | | +-----------------------+---+
+ // | | Event | | Data Buffer |
+ // +----+---------------+ | |
+ // | |
+ // +---------------------------+
//
- pSocket = pPort->pSocket;
- Status = pTcp4->RxToken.CompletionToken.Status;
- if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
- //
- // Set the buffer size and address
- //
- pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
- LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
- pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;
- pPacket->pNext = NULL;
-
- //
- // Queue this packet
- //
- bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
- if ( bUrgent ) {
- //
- // Add packet to the urgent list
- //
- pPrevious = pSocket->pRxOobPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxOobPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxOobPacketListTail = pPacket;
-
- //
- // Account for the urgent data
- //
- pSocket->RxOobBytes += LengthInBytes;
- }
- else {
- //
- // Add packet to the normal list
- //
- pPrevious = pSocket->pRxPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxPacketListTail = pPacket;
-
- //
- // Account for the normal data
- //
- pSocket->RxBytes += LengthInBytes;
- }
-
- //
- // Log the received data
- //
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",
- pPacket,
- pPort,
- LengthInBytes,
- bUrgent ? L"urgent" : L"normal" ));
-
- //
- // Attempt to restart this receive operation
- //
- if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
- EslTcpRxStart4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
- pPort,
- pSocket->RxBytes ));
- }
- }
- else
- {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
- pPacket,
- pPort,
- Status ));
-
- //
- // Receive error, free the packet save the error
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- if ( !EFI_ERROR ( pSocket->RxError )) {
- pSocket->RxError = Status;
- }
-
- //
- // Update the port state
- //
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- EslTcpPortCloseRxDone4 ( pPort );
- }
- else {
- if ( EFI_ERROR ( Status )) {
- pPort->State = PORT_STATE_RX_ERROR;
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
-
-/**
- Start a receive operation
-
- @param [in] pPort Address of the DT_PORT structure.
-
- **/
-VOID
-EslTcpRxStart4 (
- IN DT_PORT * pPort
- )
-{
- size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
//
- // Determine if a receive is already pending
+ // Duplicate the buffer address and length for use by the
+ // buffer handling code in EslTcp4Receive. These fields are
+ // used when a partial read is done of the data from the
+ // packet.
//
- Status = EFI_SUCCESS;
- pPacket = NULL;
- pSocket = pPort->pSocket;
- pTcp4 = &pPort->Context.Tcp4;
- if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
- if (( NULL == pTcp4->pReceivePending )
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
- //
- // Determine if there are any free packets
- //
- pPacket = pSocket->pRxFree;
- LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
- if ( NULL != pPacket ) {
- //
- // Remove this packet from the free list
- //
- pSocket->pRxFree = pPacket->pNext;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port removed packet 0x%08x from free list\r\n",
- pPort,
- pPacket ));
- }
- else {
- //
- // Allocate a packet structure
- //
- Status = EslSocketPacketAllocate ( &pPacket,
- sizeof ( pPacket->Op.Tcp4Rx ),
- DEBUG_RX );
- if ( EFI_ERROR ( Status )) {
- pPacket = NULL;
- DEBUG (( DEBUG_ERROR | DEBUG_RX,
- "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
-
- //
- // Determine if a packet is available
- //
- if ( NULL != pPacket ) {
- //
- // Initialize the buffer for receive
- //
- pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
- pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;
- pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
- pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;
- pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];
- pTcp4->pReceivePending = pPacket;
+ pPacket = pIo->pPacket;
+ pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
+ LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
+ pPacket->ValidBytes = LengthInBytes;
- //
- // Start the receive on the packet
- //
- pTcp4Protocol = pTcp4->pProtocol;
- Status = pTcp4Protocol->Receive ( pTcp4Protocol,
- &pTcp4->RxToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet receive pending on port 0x%08x\r\n",
- pPacket,
- pPort ));
- }
- else {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- pTcp4->pReceivePending = NULL;
- if ( !EFI_ERROR ( pSocket->RxError )) {
- //
- // Save the error status
- //
- pSocket->RxError = Status;
- }
- }
- }
- }
- }
+ //
+ // Get the data type so that it may be linked to the
+ // correct receive buffer list on the ESL_SOCKET structure
+ //
+ bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
+ //
+ // Complete this request
+ //
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
DBG_EXIT ( );
}
/**
- Shutdown the TCP4 service.
+ Start a receive operation
- This routine undoes the work performed by ::TcpInitialize4.
+ This routine posts a receive buffer to the TCPv4 driver.
+ See the \ref ReceiveEngine section.
- @param [in] pService DT_SERVICE structure address
+ 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
-EFIAPI
-EslTcpShutdown4 (
- IN DT_SERVICE * pService
+EslTcp4RxStart (
+ IN ESL_PORT * pPort,
+ IN ESL_IO_MGMT * pIo
)
{
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pPreviousService;
+ ESL_PACKET * pPacket;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Walk the list of ports
- //
- do {
- pPort = pService->pPortList;
- if ( NULL != pPort ) {
- //
- // Remove the port from the port list
- //
- pService->pPortList = pPort->pLinkService;
-
- //
- // Close the port
- // TODO: Fix this
- //
-// pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );
- }
- } while ( NULL != pPort );
-
- //
- // Remove the service from the service list
+ // Initialize the buffer for receive
//
- pLayer = &mEslLayer;
- pPreviousService = pLayer->pTcp4List;
- if ( pService == pPreviousService ) {
- //
- // Remove the service from the beginning of the list
- //
- pLayer->pTcp4List = pService->pNext;
- }
- else {
- //
- // Remove the service from the middle of the list
- //
- while ( NULL != pPreviousService ) {
- if ( pService == pPreviousService->pNext ) {
- pPreviousService->pNext = pService->pNext;
- break;
- }
- }
- }
+ pPacket = pIo->pPacket;
+ pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
+ pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
+ pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
+ pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;
+ pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];
DBG_EXIT ( );
}
@@ -2892,16 +1820,21 @@ EslTcpShutdown4 (
/**
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.
- @param [in] pSocket Address of a DT_SOCKET structure
-
@retval EFI_SUCCESS - The port is connected
@retval EFI_NOT_STARTED - The port is not connected
**/
EFI_STATUS
- EslTcpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ EslTcp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status;
@@ -2924,22 +1857,22 @@ EslTcpShutdown4 (
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
- data for transmission. When necessary, this routine will
- start the transmit engine that performs the data transmission
- on the 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.
- The transmit engine uses 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 a DT_SOCKET structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
@param [in] Flags Message control flags
@@ -2949,27 +1882,34 @@ EslTcpShutdown4 (
@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
-EslTcpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+EslTcp4TxBuffer (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength
)
{
BOOLEAN bUrgent;
- DT_PACKET * pPacket;
- DT_PACKET * pPreviousPacket;
- DT_PACKET ** ppPacket;
- DT_PACKET ** ppQueueHead;
- DT_PACKET ** ppQueueTail;
- DT_PORT * pPort;
- DT_TCP4_CONTEXT * pTcp4;
- EFI_TCP4_IO_TOKEN * pToken;
+ 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_TCP4_CONTEXT * pTcp4;
size_t * pTxBytes;
EFI_TCP4_TRANSMIT_DATA * pTxData;
EFI_STATUS Status;
@@ -2982,7 +1922,7 @@ EslTcpTxBuffer4 (
//
Status = EFI_UNSUPPORTED;
pSocket->errno = ENOTCONN;
- * pDataLength = 0;
+ *pDataLength = 0;
//
// Verify that the socket is connected
@@ -2998,18 +1938,21 @@ EslTcpTxBuffer4 (
//
pTcp4 = &pPort->Context.Tcp4;
bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
- if ( bUrgent ) {
+ bUrgentQueue = bUrgent
+ && ( !pSocket->bOobInLine )
+ && pSocket->pApi->bOobSupported;
+ if ( bUrgentQueue ) {
ppQueueHead = &pSocket->pTxOobPacketListHead;
ppQueueTail = &pSocket->pTxOobPacketListTail;
- ppPacket = &pTcp4->pTxOobPacket;
- pToken = &pTcp4->TxOobToken;
+ ppActive = &pPort->pTxOobActive;
+ ppFree = &pPort->pTxOobFree;
pTxBytes = &pSocket->TxOobBytes;
}
else {
ppQueueHead = &pSocket->pTxPacketListHead;
ppQueueTail = &pSocket->pTxPacketListTail;
- ppPacket = &pTcp4->pTxPacket;
- pToken = &pTcp4->TxToken;
+ ppActive = &pPort->pTxActive;
+ ppFree = &pPort->pTxFree;
pTxBytes = &pSocket->TxBytes;
}
@@ -3018,6 +1961,15 @@ EslTcpTxBuffer4 (
// 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
//
@@ -3025,13 +1977,14 @@ EslTcpTxBuffer4 (
sizeof ( pPacket->Op.Tcp4Tx )
- sizeof ( pPacket->Op.Tcp4Tx.Buffer )
+ BufferLength,
+ 0,
DEBUG_TX );
if ( !EFI_ERROR ( Status )) {
//
// Initialize the transmit operation
//
pTxData = &pPacket->Op.Tcp4Tx.TxData;
- pTxData->Push = TRUE;
+ pTxData->Push = TRUE || bUrgent;
pTxData->Urgent = bUrgent;
pTxData->DataLength = (UINT32) BufferLength;
pTxData->FragmentCount = 1;
@@ -3078,7 +2031,7 @@ EslTcpTxBuffer4 (
DEBUG (( DEBUG_TX,
"0x%08x: Packet on %s transmit list\r\n",
pPacket,
- bUrgent ? L"urgent" : L"normal" ));
+ bUrgentQueue ? L"urgent" : L"normal" ));
//
// Account for the buffered data
@@ -3089,12 +2042,12 @@ EslTcpTxBuffer4 (
//
// Start the transmit engine if it is idle
//
- if ( NULL == *ppPacket ) {
- EslTcpTxStart4 ( pSocket->pPortList,
- pToken,
- ppQueueHead,
- ppQueueTail,
- ppPacket );
+ if ( NULL != *ppFree ) {
+ EslSocketTxStart ( pPort,
+ ppQueueHead,
+ ppQueueTail,
+ ppActive,
+ ppFree );
}
}
else {
@@ -3124,6 +2077,14 @@ EslTcpTxBuffer4 (
}
}
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
//
@@ -3144,104 +2105,56 @@ EslTcpTxBuffer4 (
/**
Process the normal data transmit completion
- @param Event The normal transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for normal data.
- @param pPort The DT_PORT structure address
+ This routine is called by the TCPv4 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
-EslTcpTxComplete4 (
+EslTcp4TxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ 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;
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pTxPacket;
-
+
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pTcp4->pTxPacket = NULL;
LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
pSocket->TxBytes -= LengthInBytes;
-
- //
- // Save any transmit error
- //
- Status = pTcp4->TxToken.CompletionToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( pSocket->TxError )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
- //
- // Empty the normal transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxPacketListHead = NULL;
- pSocket->pTxPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslTcpTxStart4 ( pPort,
- &pTcp4->TxToken,
- &pSocket->pTxPacketListHead,
- &pSocket->pTxPacketListTail,
- &pTcp4->pTxPacket );
- }
- }
-
- //
- // Release this packet
//
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
- //
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- //
- // Indicate that the transmit is complete
- //
- EslTcpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Normal ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
DBG_EXIT ( );
}
@@ -3249,23 +2162,27 @@ EslTcpTxComplete4 (
/**
Process the urgent data transmit completion
- @param Event The urgent transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for urgent data.
- @param pPort The DT_PORT structure address
+ This routine is called by the TCPv4 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
-EslTcpTxOobComplete4 (
+EslTcp4TxOobComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_TCP4_CONTEXT * pTcp4;
+ ESL_PACKET * pPacket;
+ ESL_PORT * pPort;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -3273,150 +2190,70 @@ EslTcpTxOobComplete4 (
//
// Locate the active transmit packet
//
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
pSocket = pPort->pSocket;
- pTcp4 = &pPort->Context.Tcp4;
- pPacket = pTcp4->pTxOobPacket;
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pTcp4->pTxOobPacket = NULL;
LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
pSocket->TxOobBytes -= LengthInBytes;
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
//
- // Save any transmit error
- //
- Status = pTcp4->TxOobToken.CompletionToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( Status )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
-
-
- //
- // Empty the OOB transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxOobPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxOobPacketListHead = NULL;
- pSocket->pTxOobPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslTcpTxStart4 ( pPort,
- &pTcp4->TxOobToken,
- &pSocket->pTxOobPacketListHead,
- &pSocket->pTxOobPacketListTail,
- &pTcp4->pTxOobPacket );
- }
- }
-
- //
- // Release this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
- //
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- //
- // Indicate that the transmit is complete
- //
- EslTcpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "Urgent ",
+ &pSocket->pTxOobPacketListHead,
+ &pSocket->pTxOobPacketListTail,
+ &pPort->pTxOobActive,
+ &pPort->pTxOobFree );
DBG_EXIT ( );
}
/**
- Transmit data using a network connection.
-
-
- @param [in] pPort Address of a DT_PORT structure
- @param [in] pToken Address of either the OOB or normal transmit token
- @param [in] ppQueueHead Transmit queue head address
- @param [in] ppQueueTail Transmit queue tail address
- @param [in] ppPacket Active transmit packet address
-
- **/
-VOID
-EslTcpTxStart4 (
- IN DT_PORT * pPort,
- IN EFI_TCP4_IO_TOKEN * pToken,
- IN DT_PACKET ** ppQueueHead,
- IN DT_PACKET ** ppQueueTail,
- IN DT_PACKET ** ppPacket
- )
-{
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- EFI_TCP4_PROTOCOL * pTcp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
-
- //
- // Get the packet from the queue head
- //
- pPacket = *ppQueueHead;
- if ( NULL != pPacket ) {
- //
- // Remove the packet from the queue
- //
- pNextPacket = pPacket->pNext;
- *ppQueueHead = pNextPacket;
- if ( NULL == pNextPacket ) {
- *ppQueueTail = NULL;
- }
-
- //
- // Set the packet as active
- //
- *ppPacket = pPacket;
-
- //
- // Start the transmit operation
- //
- pTcp4Protocol = pPort->Context.Tcp4.pProtocol;
- pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;
- Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );
- if ( EFI_ERROR ( Status )) {
- pSocket = pPort->pSocket;
- if ( EFI_SUCCESS == pSocket->TxError ) {
- pSocket->TxError = Status;
- }
- }
- }
-
- DBG_EXIT ( );
-}
+ Interface between the socket layer and the network specific
+ code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
+ over TCPv4.
+**/
+CONST ESL_PROTOCOL_API cEslTcp4Api = {
+ "TCPv4",
+ IPPROTO_TCP,
+ OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pTcp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),
+ OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),
+ TRUE,
+ EADDRINUSE,
+ EslTcp4Accept,
+ EslTcp4ConnectPoll,
+ EslTcp4ConnectStart,
+ EslTcp4SocketIsConfigured,
+ EslTcp4LocalAddressGet,
+ EslTcp4LocalAddressSet,
+ EslTcp4Listen,
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslTcp4PacketFree,
+ EslTcp4PortAllocate,
+ EslTcp4PortClose,
+ EslTcp4PortCloseOp,
+ FALSE,
+ EslTcp4Receive,
+ EslTcp4RemoteAddressGet,
+ EslTcp4RemoteAddressSet,
+ EslTcp4RxComplete,
+ EslTcp4RxStart,
+ EslTcp4TxBuffer,
+ EslTcp4TxComplete,
+ EslTcp4TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/Udp4.c b/StdLib/EfiSocketLib/Udp4.c
index 95fc66517a..e1500d3f9f 100644
--- a/StdLib/EfiSocketLib/Udp4.c
+++ b/StdLib/EfiSocketLib/Udp4.c
@@ -16,633 +16,153 @@
/**
- Bind a name to a socket.
-
- The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.
-
- The configure call to the UDP4 driver occurs on the first poll, recv, recvfrom,
- send or sentto call. Until then, all changes are made in the local UDP context
- structure.
-
- @param [in] pSocket Address of the socket structure.
-
- @param [in] pSockAddr Address of a sockaddr structure that contains the
- connection point on the local machine. An IPv4 address
- of INADDR_ANY specifies that the connection is made to
- all of the network stacks on the platform. Specifying a
- specific IPv4 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] SockAddrLen Specifies the length in bytes of the sockaddr structure.
-
- @retval EFI_SUCCESS - Socket successfully created
-
- **/
-EFI_STATUS
-EslUdpBind4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
- )
-{
- EFI_HANDLE ChildHandle;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pService;
- CONST struct sockaddr_in * pIp4Address;
- EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
- EFI_STATUS Status;
- EFI_STATUS TempStatus;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
-
- //
- // Validate the address length
- //
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )
- - sizeof ( pIp4Address->sin_zero ))) {
-
- //
- // Walk the list of services
- //
- pLayer = &mEslLayer;
- pService = pLayer->pUdp4List;
- while ( NULL != pService ) {
-
- //
- // Create the UDP port
- //
- pUdp4Service = pService->pInterface;
- ChildHandle = NULL;
- Status = pUdp4Service->CreateChild ( pUdp4Service,
- &ChildHandle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Udp4 port handle created\r\n",
- ChildHandle ));
-
- //
- // Open the port
- //
- Status = EslUdpPortAllocate4 ( pSocket,
- pService,
- ChildHandle,
- (UINT8 *) &pIp4Address->sin_addr.s_addr,
- SwapBytes16 ( pIp4Address->sin_port ),
- DEBUG_BIND,
- &pPort );
- }
- else {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to open Udp4 port handle, Status: %r\r\n",
- Status ));
- ChildHandle = NULL;
- }
-
- //
- // Close the port if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
- TempStatus = pUdp4Service->DestroyChild ( pUdp4Service,
- ChildHandle );
- if ( !EFI_ERROR ( TempStatus )) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL,
- "0x%08x: Udp4 port handle destroyed\r\n",
- ChildHandle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
- "ERROR - Failed to destroy the Udp4 port handle 0x%08x, Status: %r\r\n",
- ChildHandle,
- TempStatus ));
- ASSERT ( EFI_SUCCESS == TempStatus );
- }
- }
-
- //
- // Set the next service
- //
- pService = pService->pNext;
- }
-
- //
- // Verify that at least one network connection was found
- //
- if ( NULL == pSocket->pPortList ) {
- DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
- "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
- ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
- ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
- pIp4Address->sin_addr.s_addr & 0xff,
- pIp4Address->sin_addr.s_addr ));
- pSocket->errno = EADDRNOTAVAIL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- DEBUG (( DEBUG_BIND,
- "ERROR - Invalid Udp4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
+ Get the local socket address
-/**
- Initialize the UDP4 service.
+ This routine returns the IPv4 address and UDP port number associated
+ with the local socket.
- This routine initializes the UDP4 service after its service binding
- protocol was located on a controller.
+ This routine is called by ::EslSocketGetLocalAddress to determine the
+ network address for the SOCK_DGRAM socket.
- @param [in] pService DT_SERVICE structure address
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS The service was properly initialized
- @retval other A failure occurred during the service initialization
+ @param [out] pSockAddr Network address to receive the local system address
**/
-EFI_STATUS
-EFIAPI
-EslUdpInitialize4 (
- IN DT_SERVICE * pService
+VOID
+EslUdp4LocalAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pSockAddr
)
{
- DT_LAYER * pLayer;
- EFI_STATUS Status;
+ struct sockaddr_in * pLocalAddress;
+ ESL_UDP4_CONTEXT * pUdp4;
DBG_ENTER ( );
//
- // Identify the service
- //
- pService->NetworkType = NETWORK_TYPE_UDP4;
-
- //
- // Connect this service to the service list
- //
- pLayer = &mEslLayer;
- pService->pNext = pLayer->pUdp4List;
- pLayer->pUdp4List = pService;
-
+ // Return the local address
//
- // Assume the list is empty
- //
- Status = EFI_SUCCESS;
+ pUdp4 = &pPort->Context.Udp4;
+ pLocalAddress = (struct sockaddr_in *)pSockAddr;
+ pLocalAddress->sin_family = AF_INET;
+ pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pUdp4->ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_addr ));
- //
- // Return the initialization status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
+ DBG_EXIT ( );
}
/**
- Allocate and initialize a DT_PORT structure.
+ Set the local port address.
- @param [in] pSocket Address of the socket structure.
- @param [in] pService Address of the DT_SERVICE structure.
- @param [in] ChildHandle Udp4 child handle
- @param [in] pIpAddress Buffer containing IP4 network address of the local host
- @param [in] PortNumber Udp4 port number
- @param [in] DebugFlags Flags for debug messages
- @param [out] ppPort Buffer to receive new DT_PORT structure address
+ This routine sets the local port address.
- @retval EFI_SUCCESS - Socket successfully created
+ 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 IPv4 address
+ of INADDR_ANY specifies that the connection is made to
+ all of the network stacks on the platform. Specifying a
+ specific IPv4 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
-EslUdpPortAllocate4 (
- IN DT_SOCKET * pSocket,
- IN DT_SERVICE * pService,
- IN EFI_HANDLE ChildHandle,
- IN CONST UINT8 * pIpAddress,
- IN UINT16 PortNumber,
- IN UINTN DebugFlags,
- OUT DT_PORT ** ppPort
+EslUdp4LocalAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN BOOLEAN bBindTest
)
{
- UINTN LengthInBytes;
EFI_UDP4_CONFIG_DATA * pConfig;
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_UDP4_CONTEXT * pUdp4;
+ CONST struct sockaddr_in * pIpAddress;
+ CONST UINT8 * pIpv4Address;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Use for/break instead of goto
- for ( ; ; ) {
- //
- // Allocate a port structure
- //
- pLayer = &mEslLayer;
- LengthInBytes = sizeof ( *pPort );
- Status = gBS->AllocatePool ( EfiRuntimeServicesData,
- LengthInBytes,
- (VOID **)&pPort );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "ERROR - Failed to allocate the port structure, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- pPort = NULL;
- break;
- }
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
- "0x%08x: Allocate pPort, %d bytes\r\n",
- pPort,
- LengthInBytes ));
-
- //
- // Initialize the port
- //
- ZeroMem ( pPort, LengthInBytes );
- pPort->Signature = PORT_SIGNATURE;
- pPort->pService = pService;
- pPort->pSocket = pSocket;
- pPort->pfnCloseStart = EslUdpPortCloseStart4;
- pPort->DebugFlags = DebugFlags;
-
+ // Validate the address
+ //
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
//
- // Allocate the receive event
+ // The local address must not be the broadcast address
//
- pUdp4 = &pPort->Context.Udp4;
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslUdpRxComplete4,
- pPort,
- &pUdp4->RxToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the receive event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_RX | DEBUG_POOL,
- "0x%08x: Created receive event\r\n",
- pUdp4->RxToken.Event ));
-
+ Status = EFI_INVALID_PARAMETER;
+ pPort->pSocket->errno = EADDRNOTAVAIL;
+ }
+ else {
//
- // Allocate the transmit event
+ // Set the local address
//
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
- TPL_SOCKETS,
- (EFI_EVENT_NOTIFY)EslUdpTxComplete4,
- pPort,
- &pUdp4->TxToken.Event);
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to create the transmit event, Status: %r\r\n",
- Status ));
- pSocket->errno = ENOMEM;
- break;
- }
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
- "0x%08x: Created transmit event\r\n",
- pUdp4->TxToken.Event ));
+ pIpAddress = (struct sockaddr_in *)pSockAddr;
+ pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
+ pConfig = &pPort->Context.Udp4.ConfigData;
+ pConfig->StationAddress.Addr[0] = pIpv4Address[0];
+ pConfig->StationAddress.Addr[1] = pIpv4Address[1];
+ pConfig->StationAddress.Addr[2] = pIpv4Address[2];
+ pConfig->StationAddress.Addr[3] = pIpv4Address[3];
//
- // Open the port protocol
+ // Determine if the default address is used
//
- Status = gBS->OpenProtocol (
- ChildHandle,
- &gEfiUdp4ProtocolGuid,
- (VOID **) &pUdp4->pProtocol,
- pLayer->ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
- if ( EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to open gEfiUdp4ProtocolGuid on controller 0x%08x\r\n",
- pUdp4->Handle ));
- pSocket->errno = EEXIST;
- break;
- }
- DEBUG (( DebugFlags,
- "0x%08x: gEfiUdp4ProtocolGuid opened on controller 0x%08x\r\n",
- pUdp4->pProtocol,
- ChildHandle ));
-
+ pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
+
//
- // Set the port address
+ // Set the subnet mask
//
- pUdp4->Handle = ChildHandle;
- pConfig = &pPort->Context.Udp4.ConfigData;
- pConfig->StationPort = PortNumber;
- if (( 0 == pIpAddress[0])
- && ( 0 == pIpAddress[1])
- && ( 0 == pIpAddress[2])
- && ( 0 == pIpAddress[3])) {
- pConfig->UseDefaultAddress = TRUE;
+ if ( pConfig->UseDefaultAddress ) {
+ pConfig->SubnetMask.Addr[0] = 0;
+ pConfig->SubnetMask.Addr[1] = 0;
+ pConfig->SubnetMask.Addr[2] = 0;
+ pConfig->SubnetMask.Addr[3] = 0;
}
else {
- pConfig->StationAddress.Addr[0] = pIpAddress[0];
- pConfig->StationAddress.Addr[1] = pIpAddress[1];
- pConfig->StationAddress.Addr[2] = pIpAddress[2];
- pConfig->StationAddress.Addr[3] = pIpAddress[3];
pConfig->SubnetMask.Addr[0] = 0xff;
pConfig->SubnetMask.Addr[1] = 0xff;
pConfig->SubnetMask.Addr[2] = 0xff;
pConfig->SubnetMask.Addr[3] = 0xff;
}
- pConfig->TimeToLive = 255;
- pConfig->AcceptAnyPort = FALSE;
- pConfig->AcceptBroadcast = FALSE;
- pConfig->AcceptPromiscuous = FALSE;
- pConfig->AllowDuplicatePort = TRUE;
- pConfig->DoNotFragment = TRUE;
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Add this port to the socket
- //
- pPort->pLinkSocket = pSocket->pPortList;
- pSocket->pPortList = pPort;
- DEBUG (( DebugFlags,
- "0x%08x: Socket adding port: 0x%08x\r\n",
- pSocket,
- pPort ));
-
- //
- // Add this port to the service
- //
- pPort->pLinkService = pService->pPortList;
- pService->pPortList = pPort;
-
- //
- // Return the port
- //
- *ppPort = pPort;
- break;
- }
-
- //
- // Clean up after the error if necessary
- //
- if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {
- //
- // Close the port
- //
- EslUdpPortClose4 ( pPort );
- }
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Close a UDP4 port.
-
- This routine releases the resources allocated by
- ::UdpPortAllocate4().
-
- @param [in] pPort Address of the port structure.
-
- @retval EFI_SUCCESS The port is closed
- @retval other Port close error
-
-**/
-EFI_STATUS
-EslUdpPortClose4 (
- IN DT_PORT * pPort
- )
-{
- UINTN DebugFlags;
- DT_LAYER * pLayer;
- DT_PACKET * pPacket;
- DT_PORT * pPreviousPort;
- DT_SERVICE * pService;
- DT_SOCKET * pSocket;
- EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
- pSocket = pPort->pSocket;
- pSocket->errno = 0;
- //
- // Locate the port in the socket list
- //
- pLayer = &mEslLayer;
- DebugFlags = pPort->DebugFlags;
- pPreviousPort = pSocket->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the socket list
- //
- pSocket->pPortList = pPort->pLinkSocket;
- }
- else {
//
- // Locate the port in the middle of the socket list
+ // Validate the IP address
//
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkSocket != pPort )) {
- pPreviousPort = pPreviousPort->pLinkSocket;
- }
- if ( NULL != pPreviousPort ) {
+ pConfig->StationPort = 0;
+ Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
+ : EFI_SUCCESS;
+ if ( !EFI_ERROR ( Status )) {
//
- // Remove the port from the middle of the socket list
+ // Set the port number
//
- pPreviousPort->pLinkSocket = pPort->pLinkSocket;
- }
- }
+ pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port );
- //
- // Locate the port in the service list
- //
- pService = pPort->pService;
- pPreviousPort = pService->pPortList;
- if ( pPreviousPort == pPort ) {
- //
- // Remove this port from the head of the service list
- //
- pService->pPortList = pPort->pLinkService;
- }
- else {
- //
- // Locate the port in the middle of the service list
- //
- while (( NULL != pPreviousPort )
- && ( pPreviousPort->pLinkService != pPort )) {
- pPreviousPort = pPreviousPort->pLinkService;
- }
- if ( NULL != pPreviousPort ) {
//
- // Remove the port from the middle of the service list
+ // Display the local address
//
- pPreviousPort->pLinkService = pPort->pLinkService;
- }
- }
-
- //
- // Empty the receive queue
- //
- ASSERT ( NULL == pSocket->pRxPacketListHead );
- ASSERT ( NULL == pSocket->pRxPacketListTail );
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Empty the receive free queue
- //
- while ( NULL != pSocket->pRxFree ) {
- pPacket = pSocket->pRxFree;
- pSocket->pRxFree = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
-
- //
- // Done with the receive event
- //
- pUdp4 = &pPort->Context.Udp4;
- if ( NULL != pUdp4->RxToken.Event ) {
- Status = gBS->CloseEvent ( pUdp4->RxToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed receive event\r\n",
- pUdp4->RxToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the receive event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the transmit event
- //
- if ( NULL != pUdp4->TxToken.Event ) {
- Status = gBS->CloseEvent ( pUdp4->TxToken.Event );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Closed normal transmit event\r\n",
- pUdp4->TxToken.Event ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the UDP protocol
- //
- pUdp4Service = pService->pInterface;
- if ( NULL != pUdp4->pProtocol ) {
- Status = gBS->CloseProtocol ( pUdp4->Handle,
- &gEfiUdp4ProtocolGuid,
- pLayer->ImageHandle,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags,
- "0x%08x: gEfiUdp4ProtocolGuid closed on controller 0x%08x\r\n",
- pUdp4->pProtocol,
- pUdp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags,
- "ERROR - Failed to close gEfiUdp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
- pUdp4->Handle,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Done with the UDP port
- //
- if ( NULL != pUdp4->Handle ) {
- Status = pUdp4Service->DestroyChild ( pUdp4Service,
- pUdp4->Handle );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Udp4 port handle destroyed\r\n",
- pUdp4->Handle ));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to destroy the Udp4 port handle, Status: %r\r\n",
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
+ DEBUG (( DEBUG_BIND,
+ "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfig->StationAddress.Addr[0],
+ pConfig->StationAddress.Addr[1],
+ pConfig->StationAddress.Addr[2],
+ pConfig->StationAddress.Addr[3],
+ pConfig->StationPort ));
}
}
//
- // Release the port structure
- //
- Status = gBS->FreePool ( pPort );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DebugFlags | DEBUG_POOL,
- "0x%08x: Free pPort, %d bytes\r\n",
- pPort,
- sizeof ( *pPort )));
- }
- else {
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
- "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
-
- //
- // Mark the socket as closed if necessary
- //
- if ( NULL == pSocket->pPortList ) {
- pSocket->State = SOCKET_STATE_CLOSED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
- pSocket ));
- }
-
- //
// Return the operation status
//
DBG_EXIT_STATUS ( Status );
@@ -651,288 +171,102 @@ EslUdpPortClose4 (
/**
- Start the close operation on a UDP4 port, state 1.
+ Free a receive packet
- Closing a port goes through the following states:
- 1. Port close starting - Mark the port as closing and wait for transmission to complete
- 2. Port TX close done - Transmissions complete, close the port and abort the receives
- 3. Port RX close done - Receive operations complete, close the port
- 4. Port closed - Release the port resources
-
- @param [in] pPort Address of the port structure.
- @param [in] bCloseNow Set TRUE to abort active transfers
- @param [in] DebugFlags Flags for debug messages
+ This routine performs the network specific operations necessary
+ to free a receive packet.
- @retval EFI_SUCCESS The port is closed, not normally returned
- @retval EFI_NOT_READY The port has started the closing process
- @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
- most likely the routine was called already.
+ 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
**/
-EFI_STATUS
-EslUdpPortCloseStart4 (
- IN DT_PORT * pPort,
- IN BOOLEAN bCloseNow,
- IN UINTN DebugFlags
+VOID
+EslUdp4PacketFree (
+ IN ESL_PACKET * pPacket,
+ IN OUT size_t * pRxBytes
)
{
- DT_SOCKET * pSocket;
- EFI_STATUS Status;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
+ // Account for the receive bytes
//
- VERIFY_TPL ( TPL_SOCKETS );
+ pRxData = pPacket->Op.Udp4Rx.pRxData;
+ *pRxBytes -= pRxData->DataLength;
//
- // Mark the port as closing
+ // Disconnect the buffer from the packet
//
- Status = EFI_ALREADY_STARTED;
- pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
-
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_STARTED;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
- pPort ));
- pPort->bCloseNow = bCloseNow;
- pPort->DebugFlags = DebugFlags;
-
- //
- // Determine if transmits are complete
- //
- Status = EslUdpPortCloseTxDone4 ( pPort );
- }
+ pPacket->Op.Udp4Rx.pRxData = NULL;
//
- // Return the operation status
+ // Return the buffer to the UDP4 driver
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+ DBG_EXIT ( );
}
/**
- Port close state 3
+ Initialize the network specific portions of an ::ESL_PORT structure.
- Continue the close operation after the receive is complete.
+ This routine initializes the network specific portions of an
+ ::ESL_PORT structure for use by the socket.
- @param [in] pPort Address of the port structure.
+ This support routine is called by ::EslSocketPortAllocate
+ to connect the socket with the underlying network adapter
+ running the UDPv4 protocol.
- @retval EFI_SUCCESS The port is closed
- @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.
+ @param [in] pPort Address of an ESL_PORT structure
+ @param [in] DebugFlags Flags for debug messages
-**/
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
EFI_STATUS
-EslUdpPortCloseRxDone4 (
- IN DT_PORT * pPort
+EslUdp4PortAllocate (
+ IN ESL_PORT * pPort,
+ IN UINTN DebugFlags
)
{
- PORT_STATE PortState;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_CONFIG_DATA * pConfig;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
- //
- // Verify that the port is closing
+ // Initialize the port
//
- Status = EFI_ALREADY_STARTED;
pSocket = pPort->pSocket;
- pSocket->errno = EALREADY;
- PortState = pPort->State;
- if (( PORT_STATE_CLOSE_TX_DONE == PortState )
- || ( PORT_STATE_CLOSE_DONE == PortState )) {
- //
- // Determine if the receive operation is pending
- //
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- pUdp4 = &pPort->Context.Udp4;
- if ( NULL == pUdp4->pReceivePending ) {
- //
- // The receive operation is complete
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_RX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
- pPort ));
-
- //
- // The close operation has completed
- // Release the port resources
- //
- Status = EslUdpPortClose4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Receive still pending!\r\n",
- pPort ));
- }
- }
+ pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData );
+ pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event );
+ pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData );
//
- // Return the operation status
+ // Save the cancel, receive and transmit addresses
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Port close state 2
-
- Continue the close operation after the transmission is complete.
-
- @param [in] pPort Address of the 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
-EslUdpPortCloseTxDone4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;
+ pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;
+ pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
+ pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
//
- // Verify the socket layer synchronization
- //
- VERIFY_TPL ( TPL_SOCKETS );
-
+ // Set the configuration flags
//
- // All transmissions are complete or must be stopped
- // Mark the port as TX complete
- //
- Status = EFI_ALREADY_STARTED;
- if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
- //
- // Verify that the transmissions are complete
- //
- pSocket = pPort->pSocket;
- if ( pPort->bCloseNow
- || ( EFI_SUCCESS != pSocket->TxError )
- || ( 0 == pSocket->TxBytes )) {
- //
- // Start the close operation on the port
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4Protocol = pUdp4->pProtocol;
- if ( !pUdp4->bConfigured ) {
- //
- // Skip the close operation since the port is not
- // configured
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
- pPort ));
- Status = EFI_SUCCESS;
- }
- else {
- //
- // Update the port state
- //
- pPort->State = PORT_STATE_CLOSE_TX_DONE;
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
- pPort ));
-
- //
- // Empty the receive queue
- //
- while ( NULL != pSocket->pRxPacketListHead ) {
- pPacket = pSocket->pRxPacketListHead;
- pSocket->pRxPacketListHead = pPacket->pNext;
- pSocket->RxBytes -= pPacket->Op.Udp4Rx.pRxData->DataLength;
-
- //
- // Return the buffer to the UDP4 driver
- //
- gBS->SignalEvent ( pPacket->Op.Udp4Rx.pRxData->RecycleSignal );
-
- //
- // Done with this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- pSocket->pRxPacketListTail = NULL;
- ASSERT ( 0 == pSocket->RxBytes );
-
- //
- // Reset the port, cancel the outstanding receive
- //
- Status = pUdp4Protocol->Configure ( pUdp4Protocol,
- NULL );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port reset\r\n",
- pPort ));
-
- //
- // Free the receive packet
- //
- Status = gBS->CheckEvent ( pUdp4->RxToken.Event );
- if ( EFI_SUCCESS != Status ) {
- EslSocketPacketFree ( pUdp4->pReceivePending, DEBUG_CLOSE );
- pUdp4->pReceivePending = NULL;
- Status = EFI_SUCCESS;
- }
- }
- else {
- DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
- "ERROR - Port 0x%08x reset failed, Status: %r\r\n",
- pPort,
- Status ));
- ASSERT ( EFI_SUCCESS == Status );
- }
- }
-
- //
- // Determine if the receive operation is pending
- //
- if ( !EFI_ERROR ( Status )) {
- Status = EslUdpPortCloseRxDone4 ( pPort );
- }
- }
- else {
- //
- // Transmissions are still active, exit
- //
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
- "0x%08x: Port Close: Transmits are still pending!\r\n",
- pPort ));
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
+ pConfig = &pPort->Context.Udp4.ConfigData;
+ pConfig->TimeToLive = 255;
+ pConfig->AcceptAnyPort = FALSE;
+ pConfig->AcceptBroadcast = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->AllowDuplicatePort = TRUE;
+ pConfig->DoNotFragment = TRUE;
+ Status = EFI_SUCCESS;
//
// Return the operation status
@@ -943,603 +277,192 @@ EslUdpPortCloseTxDone4 (
/**
- Connect to a remote system via the network.
+ Receive data from a network connection.
- The ::UdpConnectStart4= routine sets the remote address for the 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.
- @param [in] pSocket Address of the socket structure.
+ This routine is called by ::EslSocketReceive to handle the network
+ specific receive operation to support SOCK_DGRAM sockets.
- @param [in] pSockAddr Network address of the remote system.
-
- @param [in] SockAddrLength Length in bytes of the network address.
+ @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
- @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.
+ @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.
**/
-EFI_STATUS
-EslUdpConnect4 (
- IN DT_SOCKET * pSocket,
- IN const struct sockaddr * pSockAddr,
- IN socklen_t SockAddrLength
+UINT8 *
+EslUdp4Receive (
+ 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
)
{
- struct sockaddr_in LocalAddress;
- DT_PORT * pPort;
+ size_t DataBytes;
struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
DBG_ENTER ( );
+ pRxData = pPacket->Op.Udp4Rx.pRxData;
//
- // Assume failure
- //
- Status = EFI_NETWORK_UNREACHABLE;
- pSocket->errno = ENETUNREACH;
-
+ // Return the remote system address if requested
//
- // Get the address
- //
- pRemoteAddress = (struct sockaddr_in *)pSockAddr;
-
- //
- // Validate the address length
- //
- if ( SockAddrLength >= ( sizeof ( *pRemoteAddress )
- - sizeof ( pRemoteAddress->sin_zero ))) {
- //
- // Determine if BIND was already called
- //
- if ( NULL == pSocket->pPortList ) {
- //
- // Allow any local port
- //
- ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
- LocalAddress.sin_len = sizeof ( LocalAddress );
- LocalAddress.sin_family = AF_INET;
- Status = EslSocketBind ( &pSocket->SocketProtocol,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len,
- &pSocket->errno );
- }
-
+ if ( NULL != pAddress ) {
//
- // Walk the list of ports
+ // Build the remote address
//
- pPort = pSocket->pPortList;
- while ( NULL != pPort ) {
- //
- // Set the remote address
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
- pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
- pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
- pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
- pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
-
- //
- // At least one path exists
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
-
- //
- // Set the next port
- //
- pPort = pPort->pLinkSocket;
- }
- }
- else {
- DEBUG (( DEBUG_CONNECT,
- "ERROR - Invalid UDP4 address length: %d\r\n",
- SockAddrLength ));
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
+ DEBUG (( DEBUG_RX,
+ "Getting packet remote address: %d.%d.%d.%d:%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.SourcePort ));
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pRxData->UdpSession.SourceAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
}
//
- // Return the connect status
+ // Copy the received data
//
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
-
-
-/**
- Get the local socket address
-
- @param [in] pSocket Address of the socket structure.
-
- @param [out] pAddress Network address to receive the local system address
-
- @param [in,out] pAddressLength Length of the local network address structure
-
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
-
-**/
-EFI_STATUS
-EslUdpGetLocalAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
- struct sockaddr_in * pLocalAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
+ pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
+ (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
+ BufferLength,
+ pBuffer,
+ &DataBytes );
//
- // Verify the socket layer synchronization
+ // Determine if the data is being read
//
- VERIFY_TPL ( TPL_SOCKETS );
+ if ( *pbConsumePacket ) {
+ //
+ // Display for the bytes consumed
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ DataBytes ));
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
//
- // Verify the address length
+ // Account for any discarded data
//
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pUdp4 = &pPort->Context.Udp4;
- pLocalAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pLocalAddress, LengthInBytes );
- pLocalAddress->sin_family = AF_INET;
- pLocalAddress->sin_len = (uint8_t)LengthInBytes;
- pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
- CopyMem ( &pLocalAddress->sin_addr,
- &pUdp4->ConfigData.StationAddress.Addr[0],
- sizeof ( pLocalAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
+ *pSkipBytes = pRxData->DataLength - DataBytes;
}
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
+
//
- // Return the operation status
+ // Return the data length and the buffer address
//
- DBG_EXIT_STATUS ( Status );
- return Status;
+ *pDataLength = DataBytes;
+ DBG_EXIT_HEX ( pBuffer );
+ return pBuffer;
}
/**
Get the remote socket address
- @param [in] pSocket Address of the socket structure.
+ This routine returns the address of the remote connection point
+ associated with the SOCK_DGRAM socket.
- @param [out] pAddress Network address to receive the remote system address
+ This routine is called by ::EslSocketGetPeerAddress to detemine
+ the UDPv4 address and port number associated with the network adapter.
- @param [in,out] pAddressLength Length of the remote network address structure
+ @param [in] pPort Address of an ::ESL_PORT structure.
- @retval EFI_SUCCESS - Address available
- @retval Other - Failed to get the address
+ @param [out] pAddress Network address to receive the remote system address
**/
-EFI_STATUS
-EslUdpGetRemoteAddress4 (
- IN DT_SOCKET * pSocket,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
+VOID
+EslUdp4RemoteAddressGet (
+ IN ESL_PORT * pPort,
+ OUT struct sockaddr * pAddress
)
{
- socklen_t LengthInBytes;
- DT_PORT * pPort;
struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_STATUS Status;
+ ESL_UDP4_CONTEXT * pUdp4;
DBG_ENTER ( );
//
- // Verify the socket layer synchronization
+ // Return the remote address
//
- VERIFY_TPL ( TPL_SOCKETS );
+ pUdp4 = &pPort->Context.Udp4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ pRemoteAddress->sin_family = AF_INET;
+ pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pUdp4->ConfigData.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
- //
- // Verify that there is just a single connection
- //
- pPort = pSocket->pPortList;
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
- //
- // Verify the address length
- //
- LengthInBytes = sizeof ( struct sockaddr_in );
- if ( LengthInBytes <= * pAddressLength ) {
- //
- // Return the local address
- //
- pUdp4 = &pPort->Context.Udp4;
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- ZeroMem ( pRemoteAddress, LengthInBytes );
- pRemoteAddress->sin_family = AF_INET;
- pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
- pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
- CopyMem ( &pRemoteAddress->sin_addr,
- &pUdp4->ConfigData.RemoteAddress.Addr[0],
- sizeof ( pRemoteAddress->sin_addr ));
- pSocket->errno = 0;
- Status = EFI_SUCCESS;
- }
- else {
- pSocket->errno = EINVAL;
- Status = EFI_INVALID_PARAMETER;
- }
- }
- else {
- pSocket->errno = ENOTCONN;
- Status = EFI_NOT_STARTED;
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
+ DBG_EXIT ( );
}
/**
- Receive data from a network connection.
-
- To minimize the number of buffer copies, the ::UdpRxComplete4
- routine queues the UDP4 driver's buffer to a list of datagrams
- waiting to be received. The socket driver holds on to the
- buffers from the UDP4 driver until the application layer requests
- the data or the socket is closed.
-
- The application calls this routine in the socket layer to
- receive datagrams from one or more remote systems. This routine
- removes the next available datagram from the list of datagrams
- and copies the data from the UDP4 driver's buffer into the
- application's buffer. The UDP4 driver's buffer is then returned.
-
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @param [in] Flags Message control flags
-
- @param [in] BufferLength Length of the the buffer
+ Set the remote address
- @param [in] pBuffer Address of a buffer to receive the data.
+ This routine sets the remote address in the port.
- @param [in] pDataLength Number of received data bytes in the buffer.
+ This routine is called by ::EslSocketConnect to specify the
+ remote network address.
- @param [out] pAddress Network address to receive the remote system address
-
- @param [in,out] pAddressLength Length of the remote network address structure
-
- @retval EFI_SUCCESS - Socket data successfully received
-
-**/
-EFI_STATUS
-EslUdpReceive4 (
- IN DT_SOCKET * pSocket,
- IN INT32 Flags,
- IN size_t BufferLength,
- IN UINT8 * pBuffer,
- OUT size_t * pDataLength,
- OUT struct sockaddr * pAddress,
- IN OUT socklen_t * pAddressLength
- )
-{
- socklen_t AddressLength;
- size_t BytesToCopy;
- size_t DataBytes;
- UINT32 Fragment;
- in_addr_t IpAddress;
- size_t LengthInBytes;
- UINT8 * pData;
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- struct sockaddr_in * pRemoteAddress;
- EFI_UDP4_RECEIVE_DATA * pRxData;
- DT_UDP4_CONTEXT * pUdp4;
- struct sockaddr_in RemoteAddress;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume failure
- //
- Status = EFI_UNSUPPORTED;
- pSocket->errno = ENOTCONN;
-
- //
- // Verify that the socket is connected
- //
- if (( SOCKET_STATE_CONNECTED == pSocket->State )
- || ( PORT_STATE_RX_ERROR == pSocket->State )) {
- //
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if there is any data on the queue
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pSocket->pRxPacketListHead;
- if ( NULL != pPacket ) {
- //
- // Validate the return address parameters
- //
- pRxData = pPacket->Op.Udp4Rx.pRxData;
- if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
- //
- // Return the remote system address if requested
- //
- if ( NULL != pAddress ) {
- //
- // Build the remote address
- //
- DEBUG (( DEBUG_RX,
- "Getting packet source address: %d.%d.%d.%d:%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.SourcePort ));
- ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
- RemoteAddress.sin_len = sizeof ( RemoteAddress );
- RemoteAddress.sin_family = AF_INET;
- IpAddress = pRxData->UdpSession.SourceAddress.Addr[3];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[2];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[1];
- IpAddress <<= 8;
- IpAddress |= pRxData->UdpSession.SourceAddress.Addr[0];
- RemoteAddress.sin_addr.s_addr = IpAddress;
- RemoteAddress.sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
-
- //
- // Copy the address
- //
- pRemoteAddress = (struct sockaddr_in *)pAddress;
- AddressLength = sizeof ( *pRemoteAddress );
- if ( AddressLength > *pAddressLength ) {
- AddressLength = *pAddressLength;
- }
- CopyMem ( pRemoteAddress,
- &RemoteAddress,
- AddressLength );
-
- //
- // Update the address length
- //
- *pAddressLength = AddressLength;
- }
-
- //
- // Reduce the buffer length if necessary
- //
- DataBytes = pRxData->DataLength;
- if ( DataBytes < BufferLength ) {
- BufferLength = DataBytes;
- }
-
- //
- // Copy the received data
- //
- LengthInBytes = 0;
- Fragment = 0;
- do {
- //
- // Determine the amount of received data
- //
- pData = pRxData->FragmentTable[Fragment].FragmentBuffer;
- BytesToCopy = pRxData->FragmentTable[Fragment].FragmentLength;
- if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
- BytesToCopy = BufferLength - LengthInBytes;
- }
- LengthInBytes += BytesToCopy;
-
- //
- // 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,
- BytesToCopy ));
- CopyMem ( pBuffer, pData, BytesToCopy );
- } while ( BufferLength > LengthInBytes );
-
- //
- // Determine if the data is being read
- //
- if ( 0 == ( Flags & MSG_PEEK )) {
- //
- // Display for the bytes consumed
- //
- DEBUG (( DEBUG_RX,
- "0x%08x: Port account for 0x%08x bytes\r\n",
- pPort,
- BufferLength ));
-
- //
- // All done with this packet
- // Account for any discarded data
- //
- pSocket->RxBytes -= DataBytes;
- if ( 0 != ( DataBytes - BufferLength )) {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
- pPort,
- DataBytes - BufferLength ));
- }
-
- //
- // Remove this packet from the queue
- //
- pSocket->pRxPacketListHead = pPacket->pNext;
- if ( NULL == pSocket->pRxPacketListHead ) {
- pSocket->pRxPacketListTail = NULL;
- }
-
- //
- // Return this packet to the UDP4 driver
- //
- gBS->SignalEvent ( pRxData->RecycleSignal );
-
- //
- // Move the packet to the free queue
- //
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port freeing packet 0x%08x\r\n",
- pPort,
- pPacket ));
-
- //
- // Restart this receive operation if necessary
- //
- if (( NULL == pUdp4->pReceivePending )
- && ( MAX_RX_DATA > pSocket->RxBytes )) {
- EslUdpRxStart4 ( pPort );
- }
- }
-
- //
- // Return the data length
- //
- *pDataLength = LengthInBytes;
-
- //
- // Successful operation
- //
- Status = EFI_SUCCESS;
- pSocket->errno = 0;
- }
- else {
- //
- // Bad return address pointer and length
- //
- Status = EFI_INVALID_PARAMETER;
- pSocket->errno = EINVAL;
- }
- }
- else {
- //
- // The queue is empty
- // Determine if it is time to return the receive error
- //
- if ( EFI_ERROR ( pSocket->RxError )) {
- Status = pSocket->RxError;
- switch ( Status ) {
- default:
- pSocket->errno = EIO;
- break;
-
- case EFI_HOST_UNREACHABLE:
- pSocket->errno = EHOSTUNREACH;
- break;
-
- case EFI_NETWORK_UNREACHABLE:
- pSocket->errno = ENETUNREACH;
- break;
-
- case EFI_PORT_UNREACHABLE:
- pSocket->errno = EPROTONOSUPPORT;
- break;
-
- case EFI_PROTOCOL_UNREACHABLE:
- pSocket->errno = ENOPROTOOPT;
- break;
- }
- pSocket->RxError = EFI_SUCCESS;
- }
- else {
- Status = EFI_NOT_READY;
- pSocket->errno = EAGAIN;
- }
- }
- }
- }
-
- //
- // Return the operation status
- //
- DBG_EXIT_STATUS ( Status );
- return Status;
-}
+ @param [in] pPort Address of an ::ESL_PORT structure.
+ @param [in] pSockAddr Network address of the remote system.
-/**
- Cancel the receive operations
+ @param [in] SockAddrLength Length in bytes of the network address.
- @param [in] pSocket Address of a DT_SOCKET structure
-
- @retval EFI_SUCCESS - The cancel was successful
+ @retval EFI_SUCCESS The operation was successful
**/
EFI_STATUS
-EslUdpRxCancel4 (
- IN DT_SOCKET * pSocket
+EslUdp4RemoteAddressSet (
+ IN ESL_PORT * pPort,
+ IN CONST struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
)
{
- DT_PACKET * pPacket;
- DT_PORT * pPort;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ CONST struct sockaddr_in * pRemoteAddress;
+ ESL_UDP4_CONTEXT * pUdp4;
EFI_STATUS Status;
DBG_ENTER ( );
//
- // Assume failure
- //
- Status = EFI_NOT_FOUND;
-
+ // Set the remote address
//
- // Locate the port
- //
- pPort = pSocket->pPortList;
- if ( NULL != pPort ) {
- //
- // Determine if a receive is pending
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pReceivePending;
- if ( NULL != pPacket ) {
- //
- // Attempt to cancel the receive operation
- //
- pUdp4Protocol = pUdp4->pProtocol;
- Status = pUdp4Protocol->Cancel ( pUdp4Protocol,
- &pUdp4->RxToken );
- if ( EFI_NOT_FOUND == Status ) {
- //
- // The receive is complete
- //
- Status = EFI_SUCCESS;
- }
- }
- }
+ pUdp4 = &pPort->Context.Udp4;
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+ pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
+ pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
+ pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
+ pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
+ pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
+ Status = EFI_SUCCESS;
//
// Return the operation status
@@ -1552,351 +475,102 @@ EslUdpRxCancel4 (
/**
Process the receive completion
- Keep the UDP4 driver's buffer and append it to the list of
- datagrams for the application to receive. The UDP4 driver's
- buffer will be returned by either ::UdpReceive4 or
- ::UdpPortCloseTxDone4.
+ This routine keeps the UDPv4 driver's buffer and queues it in
+ in FIFO order to the data queue. The UDP4 driver's buffer will
+ be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.
+ See the \ref ReceiveEngine section.
- @param Event The receive completion event
+ This routine is called by the UDPv4 driver when data is
+ received.
- @param pPort The DT_PORT structure address
+ @param [in] Event The receive completion event
+
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure
**/
VOID
-EslUdpRxComplete4 (
+EslUdp4RxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
size_t LengthInBytes;
- DT_PACKET * pPacket;
- DT_PACKET * pPrevious;
+ ESL_PACKET * pPacket;
EFI_UDP4_RECEIVE_DATA * pRxData;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
EFI_STATUS Status;
DBG_ENTER ( );
-
- //
- // Mark this receive complete
- //
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pReceivePending;
- pUdp4->pReceivePending = NULL;
-
+
//
- // Determine if this receive was successful
+ // Get the operation status.
//
- pSocket = pPort->pSocket;
- Status = pUdp4->RxToken.Status;
- if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
- pRxData = pUdp4->RxToken.Packet.RxData;
- if ( PORT_STATE_CLOSE_STARTED >= pPort->State ) {
- //
- // Save the data in the packet
- //
- pPacket->Op.Udp4Rx.pRxData = pRxData;
-
- //
- // Queue this packet
- //
- pPrevious = pSocket->pRxPacketListTail;
- if ( NULL == pPrevious ) {
- pSocket->pRxPacketListHead = pPacket;
- }
- else {
- pPrevious->pNext = pPacket;
- }
- pSocket->pRxPacketListTail = pPacket;
-
- //
- // Account for the normal data
- //
- LengthInBytes = pRxData->DataLength;
- pSocket->RxBytes += LengthInBytes;
-
- //
- // Log the received data
- //
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "Received packet from: %d.%d.%d.%d:%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.SourcePort ));
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "Received packet sent to: %d.%d.%d.%d:%d\r\n",
- pRxData->UdpSession.DestinationAddress.Addr[0],
- pRxData->UdpSession.DestinationAddress.Addr[1],
- pRxData->UdpSession.DestinationAddress.Addr[2],
- pRxData->UdpSession.DestinationAddress.Addr[3],
- pRxData->UdpSession.DestinationPort ));
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of data\r\n",
- pPacket,
- pPort,
- LengthInBytes ));
-
- //
- // Attempt to restart this receive operation
- //
- if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
- EslUdpRxStart4 ( pPort );
- }
- else {
- DEBUG (( DEBUG_RX,
- "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
- pPort,
- pSocket->RxBytes ));
- }
- }
- else {
- //
- // The port is being closed
- // Return the buffer to the UDP4 driver
- //
- gBS->SignalEvent ( pRxData->RecycleSignal );
-
- //
- // Free the packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- }
- }
- else
- {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
- pPacket,
- pPort,
- Status ));
-
- //
- // Receive error, free the packet save the error
- //
- EslSocketPacketFree ( pPacket, DEBUG_RX );
- if ( !EFI_ERROR ( pSocket->RxError )) {
- pSocket->RxError = Status;
- }
-
- //
- // Update the port state
- //
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
- EslUdpPortCloseRxDone4 ( pPort );
- }
- else {
- if ( EFI_ERROR ( Status )) {
- pPort->State = PORT_STATE_RX_ERROR;
- }
- }
- }
+ Status = pIo->Token.Udp4Rx.Status;
- DBG_EXIT ( );
-}
-
-
-/**
- Start a receive operation
-
- @param [in] pPort Address of the DT_PORT structure.
-
- **/
-VOID
-EslUdpRxStart4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
//
- // Determine if a receive is already pending
+ // Get the packet length
//
- Status = EFI_SUCCESS;
- pPacket = NULL;
- pSocket = pPort->pSocket;
- pUdp4 = &pPort->Context.Udp4;
- if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
- if (( NULL == pUdp4->pReceivePending )
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
- //
- // Determine if there are any free packets
- //
- pPacket = pSocket->pRxFree;
- if ( NULL != pPacket ) {
- //
- // Remove this packet from the free list
- //
- pSocket->pRxFree = pPacket->pNext;
- DEBUG (( DEBUG_RX,
- "0x%08x: Port removed packet 0x%08x from free list\r\n",
- pPort,
- pPacket ));
- }
- else {
- //
- // Allocate a packet structure
- //
- Status = EslSocketPacketAllocate ( &pPacket,
- sizeof ( pPacket->Op.Udp4Rx ),
- DEBUG_RX );
- if ( EFI_ERROR ( Status )) {
- pPacket = NULL;
- DEBUG (( DEBUG_ERROR | DEBUG_RX,
- "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
- pPort,
- Status ));
- }
- }
-
- //
- // Determine if a packet is available
- //
- if ( NULL != pPacket ) {
- //
- // Initialize the buffer for receive
- //
- pPacket->pNext = NULL;
- pPacket->Op.Udp4Rx.pRxData = NULL;
- pUdp4->RxToken.Packet.RxData = NULL;
- pUdp4->pReceivePending = pPacket;
-
- //
- // Start the receive on the packet
- //
- pUdp4Protocol = pUdp4->pProtocol;
- Status = pUdp4Protocol->Receive ( pUdp4Protocol,
- &pUdp4->RxToken );
- if ( !EFI_ERROR ( Status )) {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "0x%08x: Packet receive pending on port 0x%08x\r\n",
- pPacket,
- pPort ));
- }
- else {
- DEBUG (( DEBUG_RX | DEBUG_INFO,
- "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
- pPort,
- Status ));
- if ( !EFI_ERROR ( pSocket->RxError )) {
- //
- // Save the error status
- //
- pSocket->RxError = Status;
- }
-
- //
- // Free the packet
- //
- pUdp4->pReceivePending = NULL;
- pPacket->pNext = pSocket->pRxFree;
- pSocket->pRxFree = pPacket;
- }
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
-
-/**
- Shutdown the UDP4 service.
-
- This routine undoes the work performed by ::UdpInitialize4.
-
- @param [in] pService DT_SERVICE structure address
-
-**/
-VOID
-EFIAPI
-EslUdpShutdown4 (
- IN DT_SERVICE * pService
- )
-{
- DT_LAYER * pLayer;
- DT_PORT * pPort;
- DT_SERVICE * pPreviousService;
-
- DBG_ENTER ( );
+ pRxData = pIo->Token.Udp4Rx.Packet.RxData;
+ LengthInBytes = pRxData->DataLength;
//
- // Verify the socket layer synchronization
+ // +--------------------+ +-----------------------+
+ // | ESL_IO_MGMT | | Data Buffer |
+ // | | | (Driver owned) |
+ // | +---------------+ +-----------------------+
+ // | | Token | ^
+ // | | Rx Event | |
+ // | | | +-----------------------+
+ // | | RxData --> | EFI_UDP4_RECEIVE_DATA |
+ // +----+---------------+ | (Driver owned) |
+ // +-----------------------+
+ // +--------------------+ ^
+ // | ESL_PACKET | .
+ // | | .
+ // | +---------------+ .
+ // | | pRxData --> NULL .......
+ // +----+---------------+
//
- VERIFY_TPL ( TPL_SOCKETS );
-
//
- // Walk the list of ports
+ // Save the data in the packet
//
- do {
- pPort = pService->pPortList;
- if ( NULL != pPort ) {
- //
- // Remove the port from the port list
- //
- pService->pPortList = pPort->pLinkService;
-
- //
- // Close the port
- // TODO: Fix this
- //
-// pPort->pfnClosePort ( pPort, 0 );
- }
- } while ( NULL != pPort );
+ pPacket = pIo->pPacket;
+ pPacket->Op.Udp4Rx.pRxData = pRxData;
//
- // Remove the service from the service list
+ // Complete this request
//
- pLayer = &mEslLayer;
- pPreviousService = pLayer->pUdp4List;
- if ( pService == pPreviousService ) {
- //
- // Remove the service from the beginning of the list
- //
- pLayer->pUdp4List = pService->pNext;
- }
- else {
- //
- // Remove the service from the middle of the list
- //
- while ( NULL != pPreviousService ) {
- if ( pService == pPreviousService->pNext ) {
- pPreviousService->pNext = pService->pNext;
- break;
- }
- }
- }
-
+ EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
DBG_EXIT ( );
}
/**
- Determine if the sockedt is configured.
+ 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
- @param [in] pSocket Address of a DT_SOCKET structure
-
@retval EFI_SUCCESS - The port is connected
@retval EFI_NOT_STARTED - The port is not connected
**/
EFI_STATUS
- EslUdpSocketIsConfigured4 (
- IN DT_SOCKET * pSocket
+ EslUdp4SocketIsConfigured (
+ IN ESL_SOCKET * pSocket
)
{
- DT_PORT * pPort;
- DT_PORT * pNextPort;
- DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_CONFIG_DATA * pConfigData;
+ ESL_PORT * pPort;
+ ESL_PORT * pNextPort;
+ ESL_UDP4_CONTEXT * pUdp4;
EFI_UDP4_PROTOCOL * pUdp4Protocol;
EFI_STATUS Status;
struct sockaddr_in LocalAddress;
@@ -1920,9 +594,10 @@ EslUdpShutdown4 (
LocalAddress.sin_family = AF_INET;
LocalAddress.sin_addr.s_addr = 0;
LocalAddress.sin_port = 0;
- Status = EslUdpBind4 ( pSocket,
- (struct sockaddr *)&LocalAddress,
- LocalAddress.sin_len );
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len,
+ &pSocket->errno );
}
//
@@ -1935,9 +610,33 @@ EslUdpShutdown4 (
//
pNextPort = pPort->pLinkSocket;
pUdp4 = &pPort->Context.Udp4;
- pUdp4Protocol = pUdp4->pProtocol;
+ pUdp4Protocol = pPort->pProtocol.UDPv4;
+ pConfigData = &pUdp4->ConfigData;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemotePort ));
Status = pUdp4Protocol->Configure ( pUdp4Protocol,
- &pUdp4->ConfigData );
+ pConfigData );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Update the configuration data
+ //
+ Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,
+ pConfigData,
+ NULL,
+ NULL,
+ NULL );
+ }
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_LISTEN,
"ERROR - Failed to configure the Udp4 port, Status: %r\r\n",
@@ -1970,15 +669,25 @@ EslUdpShutdown4 (
}
}
else {
- DEBUG (( DEBUG_LISTEN,
- "0x%08x: Port configured\r\n",
- pPort ));
- pUdp4->bConfigured = TRUE;
+ DEBUG (( DEBUG_TX,
+ "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
+ pPort,
+ pConfigData->StationAddress.Addr[0],
+ pConfigData->StationAddress.Addr[1],
+ pConfigData->StationAddress.Addr[2],
+ pConfigData->StationAddress.Addr[3],
+ pConfigData->StationPort,
+ pConfigData->RemoteAddress.Addr[0],
+ pConfigData->RemoteAddress.Addr[1],
+ pConfigData->RemoteAddress.Addr[2],
+ pConfigData->RemoteAddress.Addr[3],
+ pConfigData->RemotePort ));
+ pPort->bConfigured = TRUE;
//
// Start the first read on the port
//
- EslUdpRxStart4 ( pPort );
+ EslSocketRxStart ( pPort );
//
// The socket is connected
@@ -2018,10 +727,15 @@ EslUdpShutdown4 (
/**
Buffer data for transmission over a network connection.
- This routine is called by the socket layer API to buffer
+ 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 will start the transmit engine that
+ 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.
@@ -2030,7 +744,7 @@ EslUdpShutdown4 (
during the close operation. Only buffering errors are returned
during the current transmission attempt.
- @param [in] pSocket Address of a DT_SOCKET structure
+ @param [in] pSocket Address of an ::ESL_SOCKET structure
@param [in] Flags Message control flags
@@ -2048,8 +762,8 @@ EslUdpShutdown4 (
**/
EFI_STATUS
-EslUdpTxBuffer4 (
- IN DT_SOCKET * pSocket,
+EslUdp4TxBuffer (
+ IN ESL_SOCKET * pSocket,
IN int Flags,
IN size_t BufferLength,
IN CONST UINT8 * pBuffer,
@@ -2058,15 +772,13 @@ EslUdpTxBuffer4 (
IN socklen_t AddressLength
)
{
- DT_PACKET * pPacket;
- DT_PACKET * pPreviousPacket;
- DT_PACKET ** ppPacket;
- DT_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_PACKET * pPreviousPacket;
+ ESL_PORT * pPort;
const struct sockaddr_in * pRemoteAddress;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_COMPLETION_TOKEN * pToken;
+ ESL_UDP4_CONTEXT * pUdp4;
size_t * pTxBytes;
- DT_UDP4_TX_DATA * pTxData;
+ ESL_UDP4_TX_DATA * pTxData;
EFI_STATUS Status;
EFI_TPL TplPrevious;
@@ -2077,7 +789,7 @@ EslUdpTxBuffer4 (
//
Status = EFI_UNSUPPORTED;
pSocket->errno = ENOTCONN;
- * pDataLength = 0;
+ *pDataLength = 0;
//
// Verify that the socket is connected
@@ -2092,8 +804,6 @@ EslUdpTxBuffer4 (
// Determine the queue head
//
pUdp4 = &pPort->Context.Udp4;
- ppPacket = &pUdp4->pTxPacket;
- pToken = &pUdp4->TxToken;
pTxBytes = &pSocket->TxBytes;
//
@@ -2108,6 +818,7 @@ EslUdpTxBuffer4 (
sizeof ( pPacket->Op.Udp4Tx )
- sizeof ( pPacket->Op.Udp4Tx.Buffer )
+ BufferLength,
+ 0,
DEBUG_TX );
if ( !EFI_ERROR ( Status )) {
//
@@ -2120,16 +831,18 @@ EslUdpTxBuffer4 (
pTxData->TxData.FragmentCount = 1;
pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];
+ pTxData->RetransmitCount = 0;
//
// Set the remote system address if necessary
//
+ pTxData->TxData.UdpSessionData = NULL;
if ( NULL != pAddress ) {
pRemoteAddress = (const struct sockaddr_in *)pAddress;
- pTxData->Session.SourceAddress.Addr[0] = 0;
- pTxData->Session.SourceAddress.Addr[1] = 0;
- pTxData->Session.SourceAddress.Addr[2] = 0;
- pTxData->Session.SourceAddress.Addr[3] = 0;
+ pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];
+ pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];
+ pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];
+ pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];
pTxData->Session.SourcePort = 0;
pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
@@ -2192,8 +905,12 @@ EslUdpTxBuffer4 (
//
// Start the transmit engine if it is idle
//
- if ( NULL == pUdp4->pTxPacket ) {
- EslUdpTxStart4 ( pSocket->pPortList );
+ if ( NULL != pPort->pTxFree ) {
+ EslSocketTxStart ( pPort,
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
}
}
else {
@@ -2243,23 +960,27 @@ EslUdpTxBuffer4 (
/**
Process the transmit completion
- @param Event The normal transmit completion event
+ This routine use ::EslSocketTxComplete to perform the transmit
+ completion processing for data packets.
- @param pPort The DT_PORT structure address
+ 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
-EslUdpTxComplete4 (
+EslUdp4TxComplete (
IN EFI_EVENT Event,
- IN DT_PORT * pPort
+ IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes;
- DT_PACKET * pCurrentPacket;
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
+ ESL_PORT * pPort;
+ ESL_PACKET * pPacket;
+ ESL_SOCKET * pSocket;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -2267,142 +988,69 @@ EslUdpTxComplete4 (
//
// Locate the active transmit packet
//
+ pPacket = pIo->pPacket;
+ pPort = pIo->pPort;
pSocket = pPort->pSocket;
- pUdp4 = &pPort->Context.Udp4;
- pPacket = pUdp4->pTxPacket;
-
+
//
- // Mark this packet as complete
+ // Get the transmit length and status
//
- pUdp4->pTxPacket = NULL;
LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
pSocket->TxBytes -= LengthInBytes;
-
- //
- // Save any transmit error
- //
- Status = pUdp4->TxToken.Status;
- if ( EFI_ERROR ( Status )) {
- if ( !EFI_ERROR ( pSocket->TxError )) {
- pSocket->TxError = Status;
- }
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
- pPacket,
- Status ));
-
- //
- // Empty the normal transmit list
- //
- pCurrentPacket = pPacket;
- pNextPacket = pSocket->pTxPacketListHead;
- while ( NULL != pNextPacket ) {
- pPacket = pNextPacket;
- pNextPacket = pPacket->pNext;
- EslSocketPacketFree ( pPacket, DEBUG_TX );
- }
- pSocket->pTxPacketListHead = NULL;
- pSocket->pTxPacketListTail = NULL;
- pPacket = pCurrentPacket;
- }
- else
- {
- DEBUG (( DEBUG_TX | DEBUG_INFO,
- "0x%08x: Packet transmitted %d bytes successfully\r\n",
- pPacket,
- LengthInBytes ));
-
- //
- // Verify the transmit engine is still running
- //
- if ( !pPort->bCloseNow ) {
- //
- // Start the next packet transmission
- //
- EslUdpTxStart4 ( pPort );
- }
- }
-
- //
- // Release this packet
- //
- EslSocketPacketFree ( pPacket, DEBUG_TX );
-
+ Status = pIo->Token.Udp4Tx.Status;
+
//
- // Finish the close operation if necessary
+ // Complete the transmit operation
//
- if (( PORT_STATE_CLOSE_STARTED <= pPort->State )
- && ( NULL == pSocket->pTxPacketListHead )
- && ( NULL == pUdp4->pTxPacket )) {
- //
- // Indicate that the transmit is complete
- //
- EslUdpPortCloseTxDone4 ( pPort );
- }
+ EslSocketTxComplete ( pIo,
+ LengthInBytes,
+ Status,
+ "UDP ",
+ &pSocket->pTxPacketListHead,
+ &pSocket->pTxPacketListTail,
+ &pPort->pTxActive,
+ &pPort->pTxFree );
DBG_EXIT ( );
}
/**
- Transmit data using a network connection.
-
- @param [in] pPort Address of a DT_PORT structure
-
- **/
-VOID
-EslUdpTxStart4 (
- IN DT_PORT * pPort
- )
-{
- DT_PACKET * pNextPacket;
- DT_PACKET * pPacket;
- DT_SOCKET * pSocket;
- DT_UDP4_CONTEXT * pUdp4;
- EFI_UDP4_PROTOCOL * pUdp4Protocol;
- EFI_STATUS Status;
-
- DBG_ENTER ( );
-
- //
- // Assume success
- //
- Status = EFI_SUCCESS;
-
- //
- // Get the packet from the queue head
- //
- pSocket = pPort->pSocket;
- pPacket = pSocket->pTxPacketListHead;
- if ( NULL != pPacket ) {
- //
- // Remove the packet from the queue
- //
- pNextPacket = pPacket->pNext;
- pSocket->pTxPacketListHead = pNextPacket;
- if ( NULL == pNextPacket ) {
- pSocket->pTxPacketListTail = NULL;
- }
-
- //
- // Set the packet as active
- //
- pUdp4 = &pPort->Context.Udp4;
- pUdp4->pTxPacket = pPacket;
-
- //
- // Start the transmit operation
- //
- pUdp4Protocol = pUdp4->pProtocol;
- pUdp4->TxToken.Packet.TxData = &pPacket->Op.Udp4Tx.TxData;
- Status = pUdp4Protocol->Transmit ( pUdp4Protocol, &pUdp4->TxToken );
- if ( EFI_ERROR ( Status )) {
- pSocket = pPort->pSocket;
- if ( EFI_SUCCESS == pSocket->TxError ) {
- pSocket->TxError = Status;
- }
- }
- }
-
- DBG_EXIT ( );
-}
-
+ Interface between the socket layer and the network specific
+ code that supports SOCK_DGRAM sockets over UDPv4.
+**/
+CONST ESL_PROTOCOL_API cEslUdp4Api = {
+ "UDPv4",
+ IPPROTO_UDP,
+ OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
+ OFFSET_OF ( ESL_LAYER, pUdp4List ),
+ OFFSET_OF ( struct sockaddr_in, sin_zero ),
+ sizeof ( struct sockaddr_in ),
+ AF_INET,
+ sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
+ sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
+ OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
+ FALSE,
+ EADDRINUSE,
+ NULL, // Accept
+ NULL, // ConnectPoll
+ NULL, // ConnectStart
+ EslUdp4SocketIsConfigured,
+ EslUdp4LocalAddressGet,
+ EslUdp4LocalAddressSet,
+ NULL, // Listen
+ NULL, // OptionGet
+ NULL, // OptionSet
+ EslUdp4PacketFree,
+ EslUdp4PortAllocate,
+ NULL, // PortClose,
+ NULL, // PortCloseOp
+ TRUE,
+ EslUdp4Receive,
+ EslUdp4RemoteAddressGet,
+ EslUdp4RemoteAddressSet,
+ EslUdp4RxComplete,
+ NULL, // RxStart
+ EslUdp4TxBuffer,
+ EslUdp4TxComplete,
+ NULL // TxOobComplete
+};
diff --git a/StdLib/EfiSocketLib/UseEfiSocketLib.c b/StdLib/EfiSocketLib/UseEfiSocketLib.c
index a07b2b6e22..1c122af650 100644
--- a/StdLib/EfiSocketLib/UseEfiSocketLib.c
+++ b/StdLib/EfiSocketLib/UseEfiSocketLib.c
@@ -15,14 +15,30 @@
#include "Socket.h"
-CONST EFI_GUID mEslRawServiceGuid = {
- 0xc31bf4a5, 0x2c7, 0x49d2, { 0xa5, 0x58, 0xfe, 0x62, 0x6f, 0x7e, 0xd4, 0x77 }
+/**
+ The following GUID values are only used when an application links
+ against EfiSocketLib. An alternative set of values exists in
+ SocketDxe\EntryUnload.c which the SocketDxe driver uses to coexist
+ with socket applications.
+
+ Tag GUID - IPv4 in use by an application using EfiSocketLib
+**/
+CONST EFI_GUID mEslIp4ServiceGuid = {
+ 0x9c756011, 0x5d44, 0x4ee0, { 0xbc, 0xe7, 0xc3, 0x82, 0x18, 0xfe, 0x39, 0x8d }
};
+
+/**
+ Tag GUID - TCPv4 in use by an application using EfiSocketLib
+**/
CONST EFI_GUID mEslTcp4ServiceGuid = {
0xffc659c2, 0x4ef2, 0x4532, { 0xb8, 0x75, 0xcd, 0x9a, 0xa4, 0x27, 0x4c, 0xde }
};
+
+/**
+ Tag GUID - UDPv4 in use by an application using EfiSocketLib
+**/
CONST EFI_GUID mEslUdp4ServiceGuid = {
0x44e03a55, 0x8d97, 0x4511, { 0xbf, 0xef, 0xa, 0x8b, 0xc6, 0x2c, 0x25, 0xae }
};
@@ -31,10 +47,20 @@ CONST EFI_GUID mEslUdp4ServiceGuid = {
/**
Connect to the EFI socket library
- @param [in] ppSocketProtocol Address to receive the socket protocol address
+ This routine creates the ::ESL_SOCKET structure and returns
+ the API (::EFI_SOCKET_PROTOCOL address) to the socket file
+ system layer in BsdSocketLib.
+
+ This routine is called from the ::socket routine in BsdSocketLib
+ to create the data structure and initialize the API for a socket.
+ Note that this implementation is only used by socket applications
+ that link directly to EslSocketLib.
+
+ @param [in] ppSocketProtocol Address to receive the ::EFI_SOCKET_PROTOCOL
+ structure address
+
+ @return Value for ::errno, zero (0) indicates success.
- @retval 0 Successfully returned the socket protocol
- @retval other Value for errno
**/
int
EslServiceGetProtocol (
@@ -42,7 +68,7 @@ EslServiceGetProtocol (
)
{
EFI_HANDLE ChildHandle;
- DT_SOCKET * pSocket;
+ ESL_SOCKET * pSocket;
int RetVal;
EFI_STATUS Status;
@@ -81,6 +107,16 @@ EslServiceGetProtocol (
/**
Connect to the network layer
+ This routine is the constructor for the EfiSocketLib when the
+ library is linked directly to an application. This routine
+ walks the ::cEslSocketBinding table to create ::ESL_SERVICE
+ structures, associated with the network adapters, which this
+ routine links to the ::ESL_LAYER structure.
+
+ This routine is called from ::EslConstructor as a result of the
+ constructor redirection in ::mpfnEslConstructor at the end of this
+ file.
+
@retval EFI_SUCCESS Successfully connected to the network layer
**/
@@ -89,11 +125,12 @@ EslServiceNetworkConnect (
VOID
)
{
+ BOOLEAN bSomethingFound;
UINTN HandleCount;
- EFI_HANDLE * pHandles;
UINTN Index;
- CONST DT_SOCKET_BINDING * pSocketBinding;
- CONST DT_SOCKET_BINDING * pEnd;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ EFI_HANDLE * pHandles;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -102,13 +139,14 @@ EslServiceNetworkConnect (
// Initialize the socket layer
//
Status = EFI_SUCCESS;
+ bSomethingFound = FALSE;
EslServiceLoad ( gImageHandle );
//
// Connect the network devices
//
- pSocketBinding = &cEslSocketBinding [0];
- pEnd = &pSocketBinding [ cEslSocketBindingEntries ];
+ pSocketBinding = &cEslSocketBinding[0];
+ pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
while ( pEnd > pSocketBinding ) {
//
// Attempt to locate the network adapters
@@ -121,24 +159,30 @@ EslServiceNetworkConnect (
&HandleCount,
&pHandles );
if ( EFI_ERROR ( Status )) {
- break;
+ DEBUG (( DEBUG_ERROR,
+ "ERROR with %s layer, Status: %r\r\n",
+ pSocketBinding->pName,
+ Status ));
}
- if ( NULL != pHandles ) {
- //
- // Attempt to connect to this network adapter
- //
- for ( Index = 0; HandleCount > Index; Index++ ) {
- Status = EslServiceConnect ( gImageHandle,
- pHandles [ Index ]);
- if ( EFI_ERROR ( Status )) {
- break;
+ else {
+ if ( NULL != pHandles ) {
+ //
+ // Attempt to connect to this network adapter
+ //
+ for ( Index = 0; HandleCount > Index; Index++ ) {
+ Status = EslServiceConnect ( gImageHandle,
+ pHandles[ Index ]);
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ bSomethingFound = TRUE;
}
- }
- //
- // Done with the handles
- //
- gBS->FreePool ( pHandles );
+ //
+ // Done with the handles
+ //
+ gBS->FreePool ( pHandles );
+ }
}
//
@@ -150,6 +194,9 @@ EslServiceNetworkConnect (
//
// Return the network connection status
//
+ if ( bSomethingFound ) {
+ Status = EFI_SUCCESS;
+ }
DBG_EXIT_STATUS ( Status );
return Status;
}
@@ -158,6 +205,15 @@ EslServiceNetworkConnect (
/**
Disconnect from the network layer
+ Destructor for the EfiSocketLib when the library is linked
+ directly to an application. This routine walks the
+ ::cEslSocketBinding table to remove the ::ESL_SERVICE
+ structures (network connections) from the ::ESL_LAYER structure.
+
+ This routine is called from ::EslDestructor as a result of the
+ destructor redirection in ::mpfnEslDestructor at the end of this
+ file.
+
@retval EFI_SUCCESS Successfully disconnected from the network layer
**/
@@ -167,10 +223,10 @@ EslServiceNetworkDisconnect (
)
{
UINTN HandleCount;
- EFI_HANDLE * pHandles;
UINTN Index;
- CONST DT_SOCKET_BINDING * pSocketBinding;
- CONST DT_SOCKET_BINDING * pEnd;
+ CONST ESL_SOCKET_BINDING * pEnd;
+ EFI_HANDLE * pHandles;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
DBG_ENTER ( );
@@ -183,8 +239,8 @@ EslServiceNetworkDisconnect (
//
// Disconnect the network devices
//
- pSocketBinding = &cEslSocketBinding [0];
- pEnd = &pSocketBinding [ cEslSocketBindingEntries ];
+ pSocketBinding = &cEslSocketBinding[0];
+ pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
while ( pEnd > pSocketBinding ) {
//
// Attempt to locate the network adapters
@@ -205,7 +261,7 @@ EslServiceNetworkDisconnect (
//
for ( Index = 0; HandleCount > Index; Index++ ) {
Status = EslServiceDisconnect ( gImageHandle,
- pHandles [ Index ]);
+ pHandles[ Index ]);
if ( EFI_ERROR ( Status )) {
break;
}
@@ -238,5 +294,19 @@ EslServiceNetworkDisconnect (
}
-PFN_ESL_xSTRUCTOR mpfnEslConstructor = EslServiceNetworkConnect;
-PFN_ESL_xSTRUCTOR mpfnEslDestructor = EslServiceNetworkDisconnect;
+/**
+ Socket layer's service binding protocol delcaration.
+**/
+CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {
+ NULL,
+ NULL
+};
+
+
+/**
+ The following entries redirect the constructor and destructor
+ for any socket application that links against the EfiSocketLib.
+ Note that the SocketDxe driver uses different redirection.
+**/
+PFN_ESL_xSTRUCTOR mpfnEslConstructor = EslServiceNetworkConnect; ///< Constructor for EfiSocketLib
+PFN_ESL_xSTRUCTOR mpfnEslDestructor = EslServiceNetworkDisconnect; ///< Destructor for EfiSocketLib
diff --git a/StdLib/Include/Efi/EfiSocketLib.h b/StdLib/Include/Efi/EfiSocketLib.h
index f54d4c8fe3..802fbca40b 100644
--- a/StdLib/Include/Efi/EfiSocketLib.h
+++ b/StdLib/Include/Efi/EfiSocketLib.h
@@ -19,6 +19,7 @@
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
@@ -49,12 +50,12 @@
#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %r\n", Status )) ///< Display routine exit with status value
#define DBG_EXIT_TF(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" )) ///< Display routine with TRUE/FALSE value
#else // _MSC_VER
-#define DBG_ENTER()
-#define DBG_EXIT()
-#define DBG_EXIT_DEC(Status)
-#define DBG_EXIT_HEX(Status)
-#define DBG_EXIT_STATUS(Status)
-#define DBG_EXIT_TF(Status)
+#define DBG_ENTER() ///< Display routine entry
+#define DBG_EXIT() ///< Display routine exit
+#define DBG_EXIT_DEC(Status) ///< Display routine exit with decimal value
+#define DBG_EXIT_HEX(Status) ///< Display routine exit with hex value
+#define DBG_EXIT_STATUS(Status) ///< Display routine exit with status value
+#define DBG_EXIT_TF(Status) ///< Display routine with TRUE/FALSE value
#endif // _MSC_VER
#define DIM(x) ( sizeof ( x ) / sizeof ( x[0] )) ///< Compute the number of entries in an array
@@ -71,12 +72,27 @@
#if !defined(MDEPKG_NDEBUG)
+/**
+ Verify that the TPL is at the correct level
+**/
+#define VERIFY_AT_TPL(tpl) \
+{ \
+ EFI_TPL PreviousTpl; \
+ \
+ PreviousTpl = EfiGetCurrentTpl ( ); \
+ if ( PreviousTpl != tpl ) { \
+ DEBUG (( DEBUG_ERROR | DEBUG_TPL, \
+ "Current TPL: %d, New TPL: %d\r\n", \
+ PreviousTpl, tpl )); \
+ ASSERT ( PreviousTpl == tpl ); \
+ } \
+}
+
#define VERIFY_TPL(tpl) \
{ \
EFI_TPL PreviousTpl; \
\
- PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \
- gBS->RestoreTPL ( PreviousTpl ); \
+ PreviousTpl = EfiGetCurrentTpl ( ); \
if ( PreviousTpl > tpl ) { \
DEBUG (( DEBUG_ERROR | DEBUG_TPL, \
"Current TPL: %d, New TPL: %d\r\n", \
@@ -87,10 +103,14 @@
#else // MDEPKG_NDEBUG
-#define VERIFY_TPL(tpl)
+#define VERIFY_AT_TPL(tpl) ///< Verify that the TPL is at the correct level
+#define VERIFY_TPL(tpl) ///< Verify that the TPL is at the correct level
#endif // MDEPKG_NDEBUG
+/**
+ Raise TPL to the specified level
+**/
#define RAISE_TPL(PreviousTpl, tpl) \
VERIFY_TPL ( tpl ); \
PreviousTpl = gBS->RaiseTPL ( tpl ); \
@@ -98,29 +118,20 @@
"%d: TPL\r\n", \
tpl ))
+/**
+ Restore the TPL to the previous value
+**/
#define RESTORE_TPL(tpl) \
- gBS->RestoreTPL ( tpl ); \
DEBUG (( DEBUG_TPL | DEBUG_TPL, \
"%d: TPL\r\n", \
- tpl ))
+ tpl )); \
+ gBS->RestoreTPL ( tpl )
//------------------------------------------------------------------------------
// Data Types
//------------------------------------------------------------------------------
-typedef struct _DT_SERVICE DT_SERVICE; ///< Forward delcaration
-
-typedef
-EFI_STATUS
-(EFIAPI * PFN_SB_INITIALIZE) (
- DT_SERVICE * pService
- );
-
-typedef
-VOID
-(EFIAPI * PFN_SB_SHUTDOWN) (
- DT_SERVICE * pService
- );
+typedef struct _ESL_SERVICE ESL_SERVICE; ///< Forward delcaration
/**
Protocol binding and installation control structure
@@ -130,172 +141,190 @@ VOID
typedef struct {
CHAR16 * pName; ///< Protocol name
EFI_GUID * pNetworkBinding; ///< Network service binding protocol for socket support
+ EFI_GUID * pNetworkProtocolGuid;///< Network protocol GUID
CONST EFI_GUID * pTagGuid; ///< Tag to mark protocol in use
- PFN_SB_INITIALIZE pfnInitialize;///< Routine to initialize the service
- PFN_SB_SHUTDOWN pfnShutdown; ///< Routine to shutdown the service
-} DT_SOCKET_BINDING;
+ UINTN ServiceListOffset; ///< Offset in ::ESL_LAYER for the list of services
+ UINTN RxIo; ///< Number of receive ESL_IO_MGMT structures for data
+ UINTN TxIoNormal; ///< Number of transmit ESL_IO_MGMT structures for normal data
+ UINTN TxIoUrgent; ///< Number of transmit ESL_IO_MGMT structures for urgent data
+} ESL_SOCKET_BINDING;
//------------------------------------------------------------------------------
// GUIDs
//------------------------------------------------------------------------------
-extern CONST EFI_GUID mEslRawServiceGuid;
-extern CONST EFI_GUID mEslTcp4ServiceGuid;
-extern CONST EFI_GUID mEslUdp4ServiceGuid;
+extern CONST EFI_GUID mEslIp4ServiceGuid; ///< Tag GUID for the IPv4 layer
+extern CONST EFI_GUID mEslTcp4ServiceGuid; ///< Tag GUID for the TCPv4 layer
+extern CONST EFI_GUID mEslUdp4ServiceGuid; ///< Tag GUID for the UDPv4 layer
//------------------------------------------------------------------------------
// Data
//------------------------------------------------------------------------------
-extern CONST DT_SOCKET_BINDING cEslSocketBinding [];
-extern CONST UINTN cEslSocketBindingEntries;
+extern CONST ESL_SOCKET_BINDING cEslSocketBinding[];///< List of network service bindings
+extern CONST UINTN cEslSocketBindingEntries; ///< Number of network service bindings
//------------------------------------------------------------------------------
-// Service Support Routines
+// DXE Support Routines
//------------------------------------------------------------------------------
/**
- Connect to the network service bindings
+ Creates a child handle and installs a protocol.
- Walk the network service protocols on the controller handle and
- locate any that are not in use. Create service structures to
- manage the service binding for the socket driver.
+ When the socket application is linked against UseSocketDxe, the ::socket
+ routine indirectly calls this routine in SocketDxe to create a child
+ handle if necessary and install the socket protocol on the handle.
+ Upon return, EslServiceGetProtocol in UseSocketLib returns the
+ ::EFI_SOCKET_PROTOCOL address to the socket routine.
- @param [in] BindingHandle Handle for protocol binding.
- @param [in] Controller Handle of device to work with.
+ @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
- @retval EFI_SUCCESS This driver is added to Controller.
- @retval other This driver does not support this device.
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
+ the child
+ @retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
-EslServiceConnect (
- IN EFI_HANDLE BindingHandle,
- IN EFI_HANDLE Controller
+EslDxeCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN OUT EFI_HANDLE * pChildHandle
);
/**
- Shutdown the network connections to this controller by removing
- NetworkInterfaceIdentifier protocol and closing the DevicePath
- and PciIo protocols on Controller.
+ Destroys a child handle with a protocol installed on it.
+
+ When the socket application is linked against UseSocketDxe, the ::close
+ routine indirectly calls this routine in SocketDxe to undo the operations
+ done by the ::EslDxeCreateChild routine. This routine removes the socket
+ protocol from the handle and then destroys the child handle if there are
+ no other protocols attached.
- @param [in] BindingHandle Handle for protocol binding.
- @param [in] Controller Handle of device to stop driver on.
+ @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param [in] ChildHandle Handle of the child to destroy
- @retval EFI_SUCCESS This driver is removed Controller.
- @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
- @retval other This driver was not removed from this device.
+ @retval EFI_SUCCESS The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
+ because its services are being used.
+ @retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
-EslServiceDisconnect (
- IN EFI_HANDLE BindingHandle,
- IN EFI_HANDLE Controller
+EslDxeDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
+ IN EFI_HANDLE ChildHandle
);
/**
Install the socket service
+SocketDxe uses this routine to announce the socket interface to
+the rest of EFI.
+
@param [in] pImageHandle Address of the image handle
@retval EFI_SUCCESS Service installed successfully
**/
EFI_STATUS
EFIAPI
-EslServiceInstall (
+EslDxeInstall (
IN EFI_HANDLE * pImageHandle
);
/**
-Initialize the service layer
-
-@param [in] ImageHandle Handle for the image.
-
-**/
-VOID
-EFIAPI
-EslServiceLoad (
- IN EFI_HANDLE ImageHandle
- );
-
-/**
Uninstall the socket service
+SocketDxe uses this routine to notify EFI that the socket layer
+is no longer available.
+
@param [in] ImageHandle Handle for the image.
@retval EFI_SUCCESS Service installed successfully
**/
EFI_STATUS
EFIAPI
-EslServiceUninstall (
+EslDxeUninstall (
IN EFI_HANDLE ImageHandle
);
+//------------------------------------------------------------------------------
+// Service Support Routines
+//------------------------------------------------------------------------------
+
/**
- Shutdown the service layer
+ Connect to the network service bindings
+
+ Walk the network service protocols on the controller handle and
+ locate any that are not in use. Create ::ESL_SERVICE structures to
+ manage the network layer interfaces for the socket driver. Tag
+ each of the network interfaces that are being used. Finally, this
+ routine calls ESL_SOCKET_BINDING::pfnInitialize to prepare the network
+ interface for use by the socket layer.
+
+ @param [in] BindingHandle Handle for protocol binding.
+ @param [in] Controller Handle of device to work with.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval other This driver does not support this device.
**/
-VOID
+EFI_STATUS
EFIAPI
-EslServiceUnload (
- VOID
+EslServiceConnect (
+ IN EFI_HANDLE BindingHandle,
+ IN EFI_HANDLE Controller
);
-//------------------------------------------------------------------------------
-// Socket Service Binding Protocol Routines
-//------------------------------------------------------------------------------
-
/**
- Creates a child handle and installs a protocol.
-
- The CreateChild() function installs a protocol on ChildHandle.
- If pChildHandle is a pointer to NULL, then a new handle is created and returned in pChildHandle.
- If pChildHandle is not a pointer to NULL, then the protocol installs on the existing pChildHandle.
+ Shutdown the connections to the network layer by locating the
+ tags on the network interfaces established by ::EslServiceConnect.
+ This routine calls ESL_SOCKET_BINDING::pfnShutdown to shutdown the any
+ activity on the network interface and then free the ::ESL_SERVICE
+ structures.
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,
- then a new handle is created. If it is a pointer to an existing UEFI handle,
- then the protocol is added to the existing UEFI handle.
+ @param [in] BindingHandle Handle for protocol binding.
+ @param [in] Controller Handle of device to stop driver on.
- @retval EFI_SUCCES The protocol was added to ChildHandle.
- @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
- the child
- @retval other The child handle was not created
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval other This driver was not removed from this device.
**/
EFI_STATUS
EFIAPI
-EslSocketCreateChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN OUT EFI_HANDLE * pChildHandle
+EslServiceDisconnect (
+ IN EFI_HANDLE BindingHandle,
+ IN EFI_HANDLE Controller
);
/**
- Destroys a child handle with a protocol installed on it.
+Initialize the service layer
- The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
- that was installed by CreateChild() from ChildHandle. If the removed protocol is the
- last protocol on ChildHandle, then ChildHandle is destroyed.
+@param [in] ImageHandle Handle for the image.
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
- @param [in] ChildHandle Handle of the child to destroy
+**/
+VOID
+EFIAPI
+EslServiceLoad (
+ IN EFI_HANDLE ImageHandle
+ );
- @retval EFI_SUCCES The protocol was removed from ChildHandle.
- @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
- @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.
- @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
- because its services are being used.
- @retval other The child handle was not destroyed
+/**
+ Shutdown the service layer
**/
-EFI_STATUS
+VOID
EFIAPI
-EslSocketDestroyChild (
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,
- IN EFI_HANDLE ChildHandle
+EslServiceUnload (
+ VOID
);
//------------------------------------------------------------------------------
@@ -305,11 +334,13 @@ EslSocketDestroyChild (
/**
Bind a name to a socket.
- The ::SocketBind routine connects a name to a socket on the local machine. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls the network specific layer to save the network
+ address of the local connection point.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::bind routine calls this routine to connect a name
+ (network address and port) to a socket on the local machine.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a sockaddr structure that contains the
connection point on the local machine. An IPv4 address
@@ -321,7 +352,7 @@ EslSocketDestroyChild (
number from the dynamic range. Specifying a specific
port number causes the network layer to use that port.
- @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+ @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -331,7 +362,7 @@ EslSocketDestroyChild (
EFI_STATUS
EslSocketBind (
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
- IN const struct sockaddr * pSockAddr,
+ IN CONST struct sockaddr * pSockAddr,
IN socklen_t SockAddrLength,
OUT int * pErrno
);
@@ -339,9 +370,14 @@ EslSocketBind (
/**
Determine if the socket is closed
- Reverses the operations of the ::SocketAllocate() routine.
+ This routine checks the state of the socket to determine if
+ the network specific layer has completed the close operation.
+
+ The ::close routine polls this routine to determine when the
+ close operation is complete. The close operation needs to
+ reverse the operations of the ::EslSocketAllocate routine.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS Socket successfully closed
@@ -359,11 +395,19 @@ EslSocketClosePoll (
/**
Start the close operation on the socket
- Start closing the socket by closing all of the ports. Upon
- completion, the ::SocketPoll() routine finishes closing the
- socket.
+ This routine calls the network specific layer to initiate the
+ close state machine. This routine then calls the network
+ specific layer to determine if the close state machine has gone
+ to completion. The result from this poll is returned to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine calls this routine to start the close
+ operation which reverses the operations of the
+ ::EslSocketAllocate routine. The close routine then polls
+ the ::EslSocketClosePoll routine to determine when the
+ socket is closed.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] bCloseNow Boolean to control close behavior
@param [out] pErrno Address to receive the errno value upon completion.
@@ -383,35 +427,23 @@ EslSocketCloseStart (
/**
Connect to a remote system via the network.
- The ::SocketConnect routine attempts to establish a connection to a
- socket on the local or remote system using the specified address.
- The POSIX
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">connect</a>
- documentation is available online.
-
- There are three states associated with a connection:
- <ul>
- <li>Not connected</li>
- <li>Connection in progress</li>
- <li>Connected</li>
- </ul>
- In the "Not connected" state, calls to ::connect start the connection
- processing and update the state to "Connection in progress". During
- the "Connection in progress" state, connect polls for connection completion
- and moves the state to "Connected" after the connection is established.
- Note that these states are only visible when the file descriptor is marked
- with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection
- completes and may be used by poll or select as an indicator to call
- connect again.
-
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to establish
+ the remote system address and establish the connection to
+ the remote system.
- @param [in] pSockAddr Network address of the remote system.
+ The ::connect routine calls this routine to establish a
+ connection with the specified remote system. This routine
+ is designed to be polled by the connect routine for completion
+ of the network connection.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+ @param [in] pSockAddr Network address of the remote system.
+
@param [in] SockAddrLength Length in bytes of the network address.
-
+
@param [out] pErrno Address to receive the errno value upon completion.
-
+
@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.
@@ -428,8 +460,14 @@ EslSocketConnect (
/**
Get the local address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the network
+ address of the local host connection point.
+ The ::getsockname routine calls this routine to obtain the network
+ address associated with the local host connection point.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+
@param [out] pAddress Network address to receive the local system address
@param [in,out] pAddressLength Length of the local network address structure
@@ -450,8 +488,14 @@ EslSocketGetLocalAddress (
/**
Get the peer address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the remote
+ system connection point.
+
+ The ::getpeername routine calls this routine to obtain the network
+ address of the remote connection point.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+
@param [out] pAddress Network address to receive the remote system address
@param [in,out] pAddressLength Length of the remote network address structure
@@ -472,14 +516,18 @@ EslSocketGetPeerAddress (
/**
Establish the known port to listen for network connections.
- The ::SocketListen routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::SocketAccept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls into the network protocol layer to establish
+ a handler that is called upon connection completion. The handler
+ is responsible for inserting the connection into the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::listen routine indirectly calls this routine to place the
+ socket into a state that enables connection attempts. Connections
+ are placed in a FIFO that is serviced by the application. The
+ application calls the ::accept (::EslSocketAccept) routine to
+ remove the next connection from the FIFO and get the associated
+ socket and address.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Backlog Backlog specifies the maximum FIFO depth for
the connections waiting for the application
@@ -502,17 +550,19 @@ EslSocketListen (
/**
Get the socket options
- Retrieve the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
- @param [in] level Option protocol level
- @param [in] option_name Name of the option
- @param [out] option_value Buffer to receive the option value
- @param [in,out] option_len Length of the buffer in bytes,
- upon return length of the option value in bytes
- @param [out] pErrno Address to receive the errno value upon completion.
+ The ::getsockopt routine calls this routine to retrieve the
+ socket options one at a time by name.
+
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+ @param [in] level Option protocol level
+ @param [in] OptionName Name of the option
+ @param [out] pOptionValue Buffer to receive the option value
+ @param [in,out] pOptionLength Length of the buffer in bytes,
+ upon return length of the option value in bytes
+ @param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket data successfully received
@@ -530,18 +580,20 @@ EslSocketOptionGet (
/**
Set the socket options
- Adjust the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
+
+ The ::setsockopt routine calls this routine to adjust the socket
+ options one at a time by name.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
- @param [in] option_name Name of the option
- @param [in] option_value Buffer containing the option value
- @param [in] option_len Length of the buffer in bytes
+ @param [in] OptionName Name of the option
+ @param [in] pOptionValue Buffer containing the option value
+ @param [in] OptionLength Length of the buffer in bytes
@param [out] pErrno Address to receive the errno value upon completion.
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Option successfully set
**/
EFI_STATUS
@@ -557,10 +609,14 @@ EslSocketOptionSet (
/**
Poll a socket for pending activity.
- The SocketPoll routine checks a socket for pending activity associated
- with the event mask. Activity is returned in the detected event buffer.
+ This routine builds a detected event mask which is returned to
+ the caller in the buffer provided.
+
+ The ::poll routine calls this routine to determine if the socket
+ needs to be serviced as a result of connection, error, receive or
+ transmit activity.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
@param [in] Events Events of interest for this socket
@@ -583,15 +639,22 @@ EslSocketPoll (
/**
Receive data from a network connection.
+ This routine calls the network specific routine to remove the
+ next portion of data from the receive queue and return it to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::recvfrom routine calls this routine to determine if any data
+ is received from the remote system. Note that the other routines
+ ::recv and ::read are layered on top of ::recvfrom.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL 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 [out] pAddress Network address to receive the remote system address
@@ -618,13 +681,16 @@ EslSocketReceive (
/**
Shutdown the socket receive and transmit operations
- The SocketShutdown routine stops the socket receive and transmit
- operations.
+ This routine sets a flag to stop future transmissions and calls
+ the network specific layer to cancel the pending receive operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::shutdown routine calls this routine to stop receive and transmit
+ operations on the socket.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+
@param [in] How Which operations to stop
-
+
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket operations successfully shutdown
@@ -640,17 +706,23 @@ EslSocketShutdown (
/**
Send data using a network connection.
- The SocketTransmit routine queues the data for transmission to the
- remote network connection.
+ This routine calls the network specific layer to queue the data
+ for transmission. Eventually the buffer will reach the head of
+ the queue and will get transmitted over the network. For datagram
+ sockets there is no guarantee that the data reaches the application
+ running on the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::sendto routine calls this routine to send data to the remote
+ system. Note that ::send and ::write are layered on top of ::sendto.
+ @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
+
@param [in] Flags Message control flags
-
+
@param [in] BufferLength Length of the the buffer
-
+
@param [in] pBuffer Address of a buffer containing the data to send
-
+
@param [in] pDataLength Address to receive the number of data bytes sent
@param [in] pAddress Network address of the remote system address
@@ -659,7 +731,7 @@ EslSocketShutdown (
@param [out] pErrno Address to receive the errno value upon completion.
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Socket data successfully queued for transmit
**/
EFI_STATUS
diff --git a/StdLib/Include/Protocol/EfiSocket.h b/StdLib/Include/Protocol/EfiSocket.h
index e9e4604048..2664f01bdb 100644
--- a/StdLib/Include/Protocol/EfiSocket.h
+++ b/StdLib/Include/Protocol/EfiSocket.h
@@ -27,6 +27,9 @@
// Data Types
//------------------------------------------------------------------------------
+/**
+EfiSocketLib (SocketDxe) interface
+**/
typedef struct _EFI_SOCKET_PROTOCOL EFI_SOCKET_PROTOCOL;
/**
@@ -45,11 +48,11 @@ EFI_STATUS
// Data
//------------------------------------------------------------------------------
-extern PFN_ESL_xSTRUCTOR mpfnEslConstructor;
-extern PFN_ESL_xSTRUCTOR mpfnEslDestructor;
+extern PFN_ESL_xSTRUCTOR mpfnEslConstructor; ///< Constructor address for EslSocketLib
+extern PFN_ESL_xSTRUCTOR mpfnEslDestructor; ///< Destructor address for EslSocketLib
-extern EFI_GUID gEfiSocketProtocolGuid;
-extern EFI_GUID gEfiSocketServiceBindingProtocolGuid;
+extern EFI_GUID gEfiSocketProtocolGuid; ///< Socket protocol GUID
+extern EFI_GUID gEfiSocketServiceBindingProtocolGuid; ///< Socket layer service binding protocol GUID
//------------------------------------------------------------------------------
// Socket API
@@ -58,11 +61,16 @@ extern EFI_GUID gEfiSocketServiceBindingProtocolGuid;
/**
Accept a network connection.
- The SocketAccept routine waits for a network connection to the socket.
- It is able to return the remote network address to the caller if
- requested.
+ This routine calls the network specific layer to remove the next
+ connection from the FIFO.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::accept calls this routine to poll for a network
+ connection to the socket. When a connection is available
+ this routine returns the ::EFI_SOCKET_PROTOCOL structure address
+ associated with the new socket and the remote network address
+ if requested.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a buffer to receive the remote
network address.
@@ -71,8 +79,9 @@ extern EFI_GUID gEfiSocketServiceBindingProtocolGuid;
On output specifies the length of the
remote network address.
- @param [out] ppSocketProtocol Address of a buffer to receive the socket protocol
- instance associated with the new socket.
+ @param [out] ppSocketProtocol Address of a buffer to receive the
+ ::EFI_SOCKET_PROTOCOL instance
+ associated with the new socket.
@param [out] pErrno Address to receive the errno value upon completion.
@@ -93,11 +102,13 @@ EFI_STATUS
/**
Bind a name to a socket.
- The ::SocketBind routine connects a name to a socket on the local machine. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls the network specific layer to save the network
+ address of the local connection point.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::bind routine calls this routine to connect a name
+ (network address and port) to a socket on the local machine.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Address of a sockaddr structure that contains the
connection point on the local machine. An IPv4 address
@@ -128,9 +139,14 @@ EFI_STATUS
/**
Determine if the socket is closed
- Reverses the operations of the ::SocketAllocate() routine.
+ This routine checks the state of the socket to determine if
+ the network specific layer has completed the close operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine polls this routine to determine when the
+ close operation is complete. The close operation needs to
+ reverse the operations of the ::EslSocketAllocate routine.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS Socket successfully closed
@@ -149,11 +165,19 @@ EFI_STATUS
/**
Start the close operation on the socket
- Start closing the socket by closing all of the ports. Upon
- completion, the ::pfnClosePoll() routine finishes closing the
- socket.
+ This routine calls the network specific layer to initiate the
+ close state machine. This routine then calls the network
+ specific layer to determine if the close state machine has gone
+ to completion. The result from this poll is returned to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::close routine calls this routine to start the close
+ operation which reverses the operations of the
+ ::EslSocketAllocate routine. The close routine then polls
+ the ::EslSocketClosePoll routine to determine when the
+ socket is closed.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] bCloseNow Boolean to control close behavior
@param [out] pErrno Address to receive the errno value upon completion.
@@ -174,35 +198,23 @@ EFI_STATUS
/**
Connect to a remote system via the network.
- The ::Connect routine attempts to establish a connection to a
- socket on the local or remote system using the specified address.
- The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">POSIX</a>
- documentation is available online.
-
- There are three states associated with a connection:
- <ul>
- <li>Not connected</li>
- <li>Connection in progress</li>
- <li>Connected</li>
- </ul>
- In the "Not connected" state, calls to ::connect start the connection
- processing and update the state to "Connection in progress". During
- the "Connection in progress" state, connect polls for connection completion
- and moves the state to "Connected" after the connection is established.
- Note that these states are only visible when the file descriptor is marked
- with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection
- completes and may be used by poll or select as an indicator to call
- connect again.
+ This routine calls the network specific layer to establish
+ the remote system address and establish the connection to
+ the remote system.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::connect routine calls this routine to establish a
+ connection with the specified remote system. This routine
+ is designed to be polled by the connect routine for completion
+ of the network connection.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] pSockAddr Network address of the remote system.
-
+
@param [in] SockAddrLength Length in bytes of the network address.
-
+
@param [out] pErrno Address to receive the errno value upon completion.
-
+
@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.
@@ -220,8 +232,14 @@ EFI_STATUS
/**
Get the local address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the network
+ address of the local host connection point.
+ The ::getsockname routine calls this routine to obtain the network
+ address associated with the local host connection point.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
+
@param [out] pAddress Network address to receive the local system address
@param [in,out] pAddressLength Length of the local network address structure
@@ -243,8 +261,14 @@ EFI_STATUS
/**
Get the peer address.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ This routine calls the network specific layer to get the remote
+ system connection point.
+ The ::getpeername routine calls this routine to obtain the network
+ address of the remote connection point.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
+
@param [out] pAddress Network address to receive the remote system address
@param [in,out] pAddressLength Length of the remote network address structure
@@ -266,12 +290,16 @@ EFI_STATUS
/**
Establish the known port to listen for network connections.
- The ::SocketAisten routine places the port into a state that enables connection
- attempts. Connections are placed into FIFO order in a queue to be serviced
- by the application. The application calls the ::SocketAccept routine to remove
- the next connection from the queue and get the associated socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
- documentation for the bind routine is available online for reference.
+ This routine calls into the network protocol layer to establish
+ a handler that is called upon connection completion. The handler
+ is responsible for inserting the connection into the FIFO.
+
+ The ::listen routine indirectly calls this routine to place the
+ socket into a state that enables connection attempts. Connections
+ are placed in a FIFO that is serviced by the application. The
+ application calls the ::accept (::EslSocketAccept) routine to
+ remove the next connection from the FIFO and get the associated
+ socket and address.
@param [in] pSocketProtocol Address of the socket protocol structure.
@@ -297,11 +325,13 @@ EFI_STATUS
/**
Get the socket options
- Retrieve the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
+
+ The ::getsockopt routine calls this routine to retrieve the
+ socket options one at a time by name.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [out] pOptionValue Buffer to receive the option value
@@ -326,18 +356,20 @@ EFI_STATUS
/**
Set the socket options
- Adjust the socket options one at a time by name. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>
- documentation is available online.
+ This routine handles the socket level options and passes the
+ others to the network specific layer.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::setsockopt routine calls this routine to adjust the socket
+ options one at a time by name.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] level Option protocol level
@param [in] OptionName Name of the option
@param [in] pOptionValue Buffer containing the option value
@param [in] OptionLength Length of the buffer in bytes
@param [out] pErrno Address to receive the errno value upon completion.
- @retval EFI_SUCCESS - Socket data successfully received
+ @retval EFI_SUCCESS - Option successfully set
**/
typedef
@@ -354,10 +386,14 @@ EFI_STATUS
/**
Poll a socket for pending activity.
- The SocketPoll routine checks a socket for pending activity associated
- with the event mask. Activity is returned in the detected event buffer.
+ This routine builds a detected event mask which is returned to
+ the caller in the buffer provided.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::poll routine calls this routine to determine if the socket
+ needs to be serviced as a result of connection, error, receive or
+ transmit activity.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
@param [in] Events Events of interest for this socket
@@ -381,19 +417,22 @@ EFI_STATUS
/**
Receive data from a network connection.
- The ::recv routine waits for receive data from a remote network
- connection. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html">POSIX</a>
- documentation is available online.
+ This routine calls the network specific routine to remove the
+ next portion of data from the receive queue and return it to the
+ caller.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::recvfrom routine calls this routine to determine if any data
+ is received from the remote system. Note that the other routines
+ ::recv and ::read are layered on top of ::recvfrom.
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL 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 [out] pAddress Network address to receive the remote system address
@@ -419,53 +458,18 @@ EFI_STATUS
);
/**
- Send data using a network connection.
-
- The SocketTransmit routine queues the data for transmission to the
- remote network connection.
-
- @param [in] pSocketProtocol Address of the socket protocol structure.
-
- @param [in] Flags Message control flags
-
- @param [in] BufferLength Length of the the buffer
-
- @param [in] pBuffer Address of a buffer containing the data to send
-
- @param [in] pDataLength Address to receive the number of data bytes sent
-
- @param [in] pAddress Network address of the remote system address
-
- @param [in] AddressLength Length of the remote network address structure
-
- @param [out] pErrno Address to receive the errno value upon completion.
-
- @retval EFI_SUCCESS - Socket data successfully queued for transmission
-
- **/
-typedef
-EFI_STATUS
-(* PFN_SEND) (
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
- IN int Flags,
- IN size_t BufferLength,
- IN CONST UINT8 * pBuffer,
- OUT size_t * pDataLength,
- IN const struct sockaddr * pAddress,
- IN socklen_t AddressLength,
- IN int * pErrno
- );
-
-/**
Shutdown the socket receive and transmit operations
- The SocketShutdown routine stops the socket receive and transmit
- operations.
+ This routine sets a flag to stop future transmissions and calls
+ the network specific layer to cancel the pending receive operation.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::shutdown routine calls this routine to stop receive and transmit
+ operations on the socket.
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
+
@param [in] How Which operations to stop
-
+
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket operations successfully shutdown
@@ -482,40 +486,18 @@ EFI_STATUS
/**
Initialize an endpoint for network communication.
- The ::Socket routine initializes the communication endpoint by providing
- the support for the socket library function ::socket. The
- <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>
- documentation for the socket routine is available online for reference.
+ This routine initializes the communication endpoint.
- @param [in] pSocketProtocol Address of the socket protocol structure.
+ The ::socket routine calls this routine indirectly to create
+ the communication endpoint.
+ @param [in] pSocketProtocol Address of the socket protocol structure.
@param [in] domain Select the family of protocols for the client or server
- application.
-
- @param [in] type Specifies how to make the network connection. The following values
- are supported:
- <ul>
- <li>
- SOCK_STREAM - Connect to TCP, provides a byte stream
- that is manipluated by read, recv, send and write.
- </li>
- <li>
- SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream
- that is manipulated by read, recv, send and write.
- </li>
- <li>
- SOCK_DGRAM - Connect to UDP, provides a datagram service that is
- manipulated by recvfrom and sendto.
- </li>
- </ul>
-
- @param [in] protocol Specifies the lower layer protocol to use. The following
- values are supported:
- <ul>
- <li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>
- <li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>
- </ul>
-
+ application. See the ::socket documentation for values.
+ @param [in] type Specifies how to make the network connection.
+ See the ::socket documentation for values.
+ @param [in] protocol Specifies the lower layer protocol to use.
+ See the ::socket documentation for values.
@param [out] pErrno Address to receive the errno value upon completion.
@retval EFI_SUCCESS - Socket successfully created
@@ -534,6 +516,50 @@ EFI_STATUS
IN int * pErrno
);
+/**
+ Send data using a network connection.
+
+ This routine calls the network specific layer to queue the data
+ for transmission. Eventually the buffer will reach the head of
+ the queue and will get transmitted over the network. For datagram
+ sockets there is no guarantee that the data reaches the application
+ running on the remote system.
+
+ The ::sendto routine calls this routine to send data to the remote
+ system. Note that ::send and ::write are layered on top of ::sendto.
+
+ @param [in] pSocketProtocol Address of the ::EFI_SOCKET_PROTOCOL structure.
+
+ @param [in] Flags Message control flags
+
+ @param [in] BufferLength Length of the the buffer
+
+ @param [in] pBuffer Address of a buffer containing the data to send
+
+ @param [in] pDataLength Address to receive the number of data bytes sent
+
+ @param [in] pAddress Network address of the remote system address
+
+ @param [in] AddressLength Length of the remote network address structure
+
+ @param [out] pErrno Address to receive the errno value upon completion.
+
+ @retval EFI_SUCCESS - Socket data successfully queued for transmit
+
+ **/
+typedef
+EFI_STATUS
+(* PFN_TRANSMIT) (
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
+ IN int Flags,
+ IN size_t BufferLength,
+ IN CONST UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ IN const struct sockaddr * pAddress,
+ IN socklen_t AddressLength,
+ IN int * pErrno
+ );
+
//------------------------------------------------------------------------------
// Socket Protocol
//------------------------------------------------------------------------------
@@ -551,13 +577,13 @@ typedef struct _EFI_SOCKET_PROTOCOL {
PFN_GET_LOCAL pfnGetLocal; ///< Get local address
PFN_GET_PEER pfnGetPeer; ///< Get peer address
PFN_LISTEN pfnListen; ///< Enable connection attempts on known port
- PFN_POLL pfnPoll; ///< Poll for socket activity
PFN_OPTION_GET pfnOptionGet; ///< Get socket options
PFN_OPTION_SET pfnOptionSet; ///< Set socket options
+ PFN_POLL pfnPoll; ///< Poll for socket activity
PFN_RECEIVE pfnReceive; ///< Receive data from a socket
- PFN_SEND pfnSend; ///< Transmit data using the socket
PFN_SHUTDOWN pfnShutdown; ///< Shutdown receive and transmit operations
PFN_SOCKET pfnSocket; ///< Initialize the socket
+ PFN_TRANSMIT pfnTransmit; ///< Transmit data using the socket
} GCC_EFI_SOCKET_PROTOCOL;
//------------------------------------------------------------------------------
@@ -565,9 +591,7 @@ typedef struct _EFI_SOCKET_PROTOCOL {
//------------------------------------------------------------------------------
/**
- Non blocking version of accept.
-
- See ::accept
+ Non blocking version of ::accept.
@param [in] s Socket file descriptor returned from ::socket.
@@ -578,7 +602,7 @@ typedef struct _EFI_SOCKET_PROTOCOL {
contains the length of the remote network address.
@return This routine returns zero if successful and -1 when an error occurs.
- In the case of an error, errno contains more details.
+ In the case of an error, ::errno contains more details.
**/
int
@@ -589,12 +613,12 @@ AcceptNB (
);
/**
- Connect to the socket driver
+ Connect to the EFI socket library
@param [in] ppSocketProtocol Address to receive the socket protocol address
- @retval 0 Successfully returned the socket protocol
- @retval other Value for errno
+ @return Value for ::errno, zero (0) indicates success.
+
**/
int
EslServiceGetProtocol (
diff --git a/StdLib/SocketDxe/ComponentName.c b/StdLib/SocketDxe/ComponentName.c
index 7fe9c711ee..ff1f101516 100644
--- a/StdLib/SocketDxe/ComponentName.c
+++ b/StdLib/SocketDxe/ComponentName.c
@@ -17,7 +17,7 @@
/**
EFI Component Name Protocol declaration
**/
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
GetDriverName,
GetControllerName,
"eng"
@@ -26,7 +26,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
/**
EFI Component Name 2 Protocol declaration
**/
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName,
"en"
@@ -91,7 +91,7 @@ GetDriverName (
pThis->SupportedLanguages,
mDriverNameTable,
ppDriverName,
- (BOOLEAN)(pThis == &gComponentName)
+ (BOOLEAN)(pThis == &mComponentName)
);
return Status;
}
diff --git a/StdLib/SocketDxe/DriverBinding.c b/StdLib/SocketDxe/DriverBinding.c
index 7de7f62a35..4d68f37be2 100644
--- a/StdLib/SocketDxe/DriverBinding.c
+++ b/StdLib/SocketDxe/DriverBinding.c
@@ -10,6 +10,31 @@
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 NetworkAdapterManagement Network Adapter Management
+ Network adapters may come and go over the life if a system running
+ UEFI. The SocketDxe driver uses the driver binding API to manage
+ the connections to network adapters.
+
+ The ::DriverSupported routine selects network adapters that the
+ socket layer is not using. This determination by the lack of the
+ tag GUID associated with the network protocol in the
+ ::cEslSocketBinding array. The selected network adapters are
+ passed to the ::DriverStart routine.
+
+ The ::DriverStart routine calls the ::EslServiceConnect routine
+ to create an ::ESL_SERVICE structure to manage the network adapter
+ for the socket layer. EslServiceConnect also installs the tag
+ GUID on the network adapter to prevent future calls from
+ ::DriverSupported. EslService also calls the network specific
+ initialization routine listed in ESL_SOCKET_BINDING::pfnInitialize
+ field of the ::cEslSocketBinding entry.
+
+ The ::DriverStop routine calls the ::EslServiceDisconnect routine
+ to undo the work done by ::DriverStart. The socket layer must break
+ the active network connections, then remove the tag GUIDs from the
+ controller handle and free ::ESL_SERVICE structure.
+
**/
#include "Socket.h"
@@ -17,10 +42,17 @@
/**
Verify the controller type
- Determine if any of the network service binding protocols exist on
- the controller handle. If so, verify that these protocols are not
- already in use. Call ::DriverStart for any network service binding
- protocol that is not in use.
+ This routine walks the cEslSocketBinding array to determines if
+ the controller is a network adapter by supporting any of the
+ network protocols required by the sockets layer. If so, the
+ routine verifies that the socket layer is not already using the
+ support by looking for the tag GUID listed in the corresponding
+ array entry. The controller handle is passed to the ::DriverStart
+ routine if sockets can use the network adapter.
+ See the \ref NetworkAdapterManagement section.
+
+ This routine is called by the UEFI driver framework during connect
+ processing.
@param [in] pThis Protocol instance pointer.
@param [in] Controller Handle of device to test.
@@ -38,9 +70,9 @@ DriverSupported (
IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath
)
{
- CONST DT_SOCKET_BINDING * pEnd;
+ CONST ESL_SOCKET_BINDING * pEnd;
VOID * pInterface;
- CONST DT_SOCKET_BINDING * pSocketBinding;
+ CONST ESL_SOCKET_BINDING * pSocketBinding;
EFI_STATUS Status;
//
@@ -104,11 +136,14 @@ DriverSupported (
/**
- Connect to the network service bindings
+ Connect to a network adapter
- Walk the network service protocols on the controller handle and
- locate any that are not in use. Create service structures to
- manage the service binding for the socket driver.
+ This routine calls ::EslServiceConnect to connect the socket
+ layer to the network adapters. See the \ref NetworkAdapterManagement
+ section.
+
+ This routine is called by the UEFI driver framework during connect
+ processing if the controller passes the tests in ::DriverSupported.
@param [in] pThis Protocol instance pointer.
@param [in] Controller Handle of device to work with.
@@ -145,9 +180,17 @@ DriverStart (
/**
- Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
- closing the DevicePath and PciIo protocols on Controller.
+ Disconnect from a network adapter
+
+ This routine calls ::EslServiceDisconnect to disconnect the socket
+ layer from the network adapters. See the \ref NetworkAdapterManagement
+ section.
+ This routine is called by ::DriverUnload when the socket layer
+ is being unloaded. This routine should also called by the UEFI
+ driver framework when a network adapter is being unloaded from
+ the system.
+
@param [in] pThis Protocol instance pointer.
@param [in] Controller Handle of device to stop driver on.
@param [in] NumberOfChildren How many children need to be stopped.
@@ -186,9 +229,9 @@ DriverStop (
/**
- Driver binding protocol definition
+ Driver binding protocol for the SocketDxe driver.
**/
-EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
+EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
DriverSupported,
DriverStart,
DriverStop,
diff --git a/StdLib/SocketDxe/EntryUnload.c b/StdLib/SocketDxe/EntryUnload.c
index 6afd8e6b48..1f550c95b3 100644
--- a/StdLib/SocketDxe/EntryUnload.c
+++ b/StdLib/SocketDxe/EntryUnload.c
@@ -15,14 +15,31 @@
#include "Socket.h"
-CONST EFI_GUID mEslRawServiceGuid = {
- 0xf9f5d280, 0x8a4b, 0x48e2, { 0x96, 0x28, 0xda, 0xfa, 0xa7, 0x70, 0x54, 0x5d }
+/**
+ The following GUID values are only used by the SocketDxe driver. An
+ alternative set of values exists in EfiSocketLib\UseEfiSocketLib.c
+ which an application uses when it links against EfiSocketLib. These
+ two sets of values allow the SocketDxe driver to coexist with socket
+ applications.
+
+ Tag GUID - IPv4 in use by SocketDxe
+**/
+CONST EFI_GUID mEslIp4ServiceGuid = {
+ 0x4e3a82e6, 0xe43f, 0x460a, { 0x86, 0x6e, 0x9b, 0x5a, 0xab, 0x80, 0x44, 0x48 }
};
+
+/**
+ Tag GUID - TCPv4 in use by SocketDxe
+**/
CONST EFI_GUID mEslTcp4ServiceGuid = {
0x4dcaab0a, 0x1990, 0x4352, { 0x8d, 0x2f, 0x2d, 0x8f, 0x13, 0x55, 0x98, 0xa5 }
};
+
+/**
+ Tag GUID - UDPv4 in use by SocketDxe
+**/
CONST EFI_GUID mEslUdp4ServiceGuid = {
0x43a110ce, 0x9ccd, 0x402b, { 0x8c, 0x29, 0x4a, 0x6d, 0x8a, 0xf7, 0x79, 0x90 }
};
@@ -98,7 +115,7 @@ DriverUnload (
//
Max = BufferSize / sizeof ( pHandle[ 0 ]);
for ( Index = 0; Max > Index; Index++ ) {
- Status = DriverStop ( &gDriverBinding,
+ Status = DriverStop ( &mDriverBinding,
pHandle[ Index ],
0,
NULL );
@@ -131,7 +148,7 @@ DriverUnload (
// Done with the socket layer
//
if ( !EFI_ERROR ( Status )) {
- Status = EslServiceUninstall ( ImageHandle );
+ Status = EslDxeUninstall ( ImageHandle );
if ( !EFI_ERROR ( Status )) {
//
// Remove the protocols installed by the EntryPoint routine.
@@ -139,11 +156,11 @@ DriverUnload (
Status = gBS->UninstallMultipleProtocolInterfaces (
ImageHandle,
&gEfiDriverBindingProtocolGuid,
- &gDriverBinding,
+ &mDriverBinding,
&gEfiComponentNameProtocolGuid,
- &gComponentName,
+ &mComponentName,
&gEfiComponentName2ProtocolGuid,
- &gComponentName2,
+ &mComponentName2,
NULL
);
if ( !EFI_ERROR ( Status )) {
@@ -225,10 +242,10 @@ EntryPoint (
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
pSystemTable,
- &gDriverBinding,
+ &mDriverBinding,
ImageHandle,
- &gComponentName,
- &gComponentName2
+ &mComponentName,
+ &mComponentName2
);
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
@@ -250,7 +267,7 @@ EntryPoint (
// Make the socket serivces available to other drivers
// and applications
//
- Status = EslServiceInstall ( &ImageHandle );
+ Status = EslDxeInstall ( &ImageHandle );
if ( EFI_ERROR ( Status )) {
//
// Disconnect from the network
@@ -263,11 +280,11 @@ EntryPoint (
gBS->UninstallMultipleProtocolInterfaces (
ImageHandle,
&gEfiDriverBindingProtocolGuid,
- &gDriverBinding,
+ &mDriverBinding,
&gEfiComponentNameProtocolGuid,
- &gComponentName,
+ &mComponentName,
&gEfiComponentName2ProtocolGuid,
- &gComponentName2,
+ &mComponentName2,
NULL
);
DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
@@ -292,5 +309,19 @@ EntryPoint (
}
-PFN_ESL_xSTRUCTOR mpfnEslConstructor = NULL;
-PFN_ESL_xSTRUCTOR mpfnEslDestructor = NULL;
+/**
+ Socket layer's service binding protocol delcaration.
+**/
+CONST EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {
+ EslDxeCreateChild,
+ EslDxeDestroyChild
+};
+
+
+/**
+ The following entries disable the constructor and destructor
+ for the SocketDxe driver. Note that socket applications linking
+ against EfiSocketLib use different redirection.
+**/
+PFN_ESL_xSTRUCTOR mpfnEslConstructor = NULL; ///< No EfiSocketLib constructor needed for SocketDxe
+PFN_ESL_xSTRUCTOR mpfnEslDestructor = NULL; ///< No EfiSocketLib destructor needed for SocketDxe
diff --git a/StdLib/SocketDxe/Socket.h b/StdLib/SocketDxe/Socket.h
index dfa4dad51b..7d8334c4a6 100644
--- a/StdLib/SocketDxe/Socket.h
+++ b/StdLib/SocketDxe/Socket.h
@@ -23,9 +23,9 @@
// Protocol Declarations
//------------------------------------------------------------------------------
-extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; ///< Component name protocol declaration
-extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; ///< Component name 2 protocol declaration
-extern EFI_DRIVER_BINDING_PROTOCOL gDriverBinding; ///< Driver binding protocol declaration
+extern EFI_COMPONENT_NAME_PROTOCOL mComponentName; ///< Component name protocol declaration
+extern EFI_COMPONENT_NAME2_PROTOCOL mComponentName2; ///< Component name 2 protocol declaration
+extern EFI_DRIVER_BINDING_PROTOCOL mDriverBinding; ///< Driver binding protocol declaration
extern EFI_SERVICE_BINDING_PROTOCOL mServiceBinding; ///< Service binding protocol delcaration
//------------------------------------------------------------------------------
diff --git a/StdLib/UseSocketDxe/UseSocketDxe.c b/StdLib/UseSocketDxe/UseSocketDxe.c
index 0b7194c234..6074143264 100644
--- a/StdLib/UseSocketDxe/UseSocketDxe.c
+++ b/StdLib/UseSocketDxe/UseSocketDxe.c
@@ -23,12 +23,26 @@
/**
- Connect to the socket driver
+ Connect to the EFI socket library
- @param [in] ppSocketProtocol Address to receive the socket protocol address
+ This routine establishes a connection to the socket driver
+ and returns the API (::EFI_SOCKET_PROTOCOL address) to the
+ socket file system layer in BsdSocketLib. This routine looks for
+ the gEfiSocketServiceBindingProtocolGuid to locate the socket
+ driver. This routine then creates a child handle and locates
+ the gEfiSocketProtocolGuid protocol on that handle to get the
+ ::EFI_SOCKET_PROTOCOL structure address.
+
+ This routine is called from the ::socket routine in BsdSocketLib
+ to create the data structure and initialize the API for a socket.
+ Note that this implementation is only used by socket applications
+ that link directly to UseSocketDxe.
+
+ @param [in] ppSocketProtocol Address to receive the ::EFI_SOCKET_PROTOCOL
+ structure address
+
+ @return Value for ::errno, zero (0) indicates success.
- @retval 0 Successfully returned the socket protocol
- @retval other Value for errno
**/
int
EslServiceGetProtocol (
@@ -148,7 +162,7 @@ EslServiceGetProtocol (
}
else {
DEBUG (( DEBUG_ERROR,
- "ERROR - No socket service binding protocol, Status: %r\r\n",
+ "ERROR - Socket driver not loaded, Status: %r\r\n",
Status ));
RetVal = ENODEV;
}