1/** @file
2  Implement the socket support for the socket layer.
3
4  Socket States:
5  * Bound - pSocket->PortList is not NULL
6  * Listen - AcceptWait event is not NULL
7
8  Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
9  This program and the accompanying materials are licensed and made available under
10  the terms and conditions of the BSD License that accompanies this distribution.
11  The full text of the license may be found at
12  http://opensource.org/licenses/bsd-license.php
13
14  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17
18  \section DataStructures Data Structures
19
20  <code><pre>
21
22                +---------------+   +-------------+   +-------------+
23  Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
24                +---------------+   +-------------+   +-------------+
25                  ^                       | (pPortList)    |
26    pUdp4List ^   | pTcp4List             |                |
27              |   |                       |                |
28          ^   |   |                       |                |
29 pIp4List |   |   |                       |                |
30        +---------------+                 |                |
31        | ::ESL_LAYER   | ::mEslLayer     |                |
32        +---------------+                 |                |
33                  | (pSocketList)         |                |
34    Socket List   V                       V                V
35                +---------------+   +-------------+   +-------------+
36                | ::ESL_SOCKET  |-->| ::ESL_PORT  |-->|   ESL_PORT  |--> NULL (pLinkSocket)
37                +---------------+   +-------------+   +-------------+
38                  |                       |                |
39                  |                       |                V
40                  V                       V               NULL
41                +-------------+   +-------------+
42                | ESL_SOCKET  |-->|   ESL_PORT  |--> NULL
43                +-------------+   +-------------+
44                  |    | | | |            |
45                  V    | | | |            V
46                 NULL  | | | |           NULL
47               (pNext) | | | |     (pLinkService)
48                       | | | |                                     pRxPacketListHead
49                       | | | `-----------------------------------------------.
50                       | | |                     pRxOobPacketListHead        |
51                       | | `--------------------------------.                |
52                       | |      pTxPacketListHead           |                |
53                       | `---------------.                  |                |
54  pTxOobPacketListHead |                 |                  |                |
55                       V                 V                  V                V
56                  +--------------+    +------------+    +------------+    +------------+
57                  | ::ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
58                  +--------------+    +------------+    +------------+    +------------+
59                         |                 |                |                |
60                         V                 V                V                V
61                  +------------+    +------------+    +------------+    +------------+
62                  | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
63                  +------------+    +------------+    +------------+    +------------+
64                         |                 |                |                |
65                         V                 V                V                V
66                        NULL              NULL             NULL             NULL
67                       (pNext)
68
69  </pre></code>
70
71  ::mEslLayer is the one and only ::ESL_LAYER structure.  It connects directly or
72  indirectly to the other data structures.  The ESL_LAYER structure has a unique
73  service list for each of the network protocol interfaces.
74
75  ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
76
77  ::ESL_SOCKET manages the activity for a single socket instance.  As such, it contains
78  the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
79  reference and the API into the EFI socket library.
80
81  ::ESL_PORT manages the connection with a single instance of the lower layer network.
82  This structure is the socket equivalent of an IP connection or a TCP or UDP port.
83
84  ::ESL_PACKET buffers data for transmit and receive.  There are four queues connected
85  to the ::ESL_SOCKET that manage the data:
86  <ul>
87    <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
88    <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
89    <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
90    <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
91  </ul>
92  The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
93  request as well as the socket option SO_OOBINLINE.  The receive queue is selected by
94  the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
95
96  Data structure synchronization is done by raising TPL to TPL_SOCKET.  Modifying
97  critical elements within the data structures must be done at this TPL.  TPL is then
98  restored to the previous level.  Note that the code verifies that all callbacks are
99  entering at TPL_SOCKETS for proper data structure synchronization.
100
101  \section PortCloseStateMachine Port Close State Machine
102
103  The port close state machine walks the port through the necessary
104  states to stop activity on the port and get it into a state where
105  the resources may be released.  The state machine consists of the
106  following arcs and states:
107
108  <code><pre>
109
110      +--------------------------+
111      |          Open            |
112      +--------------------------+
113                   |
114                   |  ::EslSocketPortCloseStart
115                   V
116      +--------------------------+
117      | PORT_STATE_CLOSE_STARTED |
118      +--------------------------+
119                   |
120                   |  ::EslSocketPortCloseTxDone
121                   V
122      +--------------------------+
123      | PORT_STATE_CLOSE_TX_DONE |
124      +--------------------------+
125                   |
126                   |  ::EslSocketPortCloseComplete
127                   V
128      +--------------------------+
129      |  PORT_STATE_CLOSE_DONE   |
130      +--------------------------+
131                   |
132                   |  ::EslSocketPortCloseRxDone
133                   V
134      +--------------------------+
135      | PORT_STATE_CLOSE_RX_DONE |
136      +--------------------------+
137                   |
138                   |  ::EslSocketPortClose
139                   V
140      +--------------------------+
141      |          Closed          |
142      +--------------------------+
143
144  </pre></code>
145
146  <ul>
147    <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
148      initiates the port close operation</li>
149    <li>State: PORT_STATE_CLOSE_STARTED</li>
150    <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
151      operations to complete.  After all of the transmits are complete,
152      this routine initiates the network specific close operation by calling
153      through ESL_PROTOCOL_API::pfnPortCloseOp.  One such routine is
154      ::EslTcp4PortCloseOp.
155    </li>
156    <li>State: PORT_STATE_CLOSE_TX_DONE</li>
157    <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
158      complete.  After the transition to PORT_STATE_CLOSE_DONE,
159      this routine calls ::EslSocketRxCancel to abort the pending receive operations.
160    </li>
161    <li>State: PORT_STATE_CLOSE_DONE</li>
162    <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
163      operation have been cancelled.  After the transition to
164      PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
165    </li>
166    <li>State: PORT_STATE_CLOSE_RX_DONE</li>
167    <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
168      using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
169      This routine then releases the port resources allocated by ::EslSocketPortAllocate
170      and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
171      via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
172    </li>
173  </ul>
174
175
176  \section ReceiveEngine Receive Engine
177
178  The receive path accepts data from the network and queues (buffers) it for the
179  application.  Flow control is applied once a maximum amount of buffering is reached
180  and is released when the buffer usage drops below that limit.  Eventually the
181  application requests data from the socket which removes entries from the queue and
182  returns the data.
183
184  The receive engine is the state machine which reads data from the network and
185  fills the queue with received packets.  The receive engine uses two data structures
186  to manage the network receive opeations and the buffers.
187
188  At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
189  events for the interface to the UEFI network stack.  The ::ESL_PACKET
190  structures are managing the receive data buffers.  The receive engine
191  connects these two structures in the network specific receive completion
192  routines.
193
194<code><pre>
195
196      +------------------+
197      |     ::ESL_PORT     |
198      |                  |
199      +------------------+
200      |    ::ESL_IO_MGMT   |
201      +------------------+
202      |    ESL_IO_MGMT   |
203      +------------------+
204      .                  .
205      .    ESL_IO_MGMT   .
206      .                  .
207      +------------------+
208
209</pre></code>
210
211  The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
212  ::EslSocketPortAllocate.  The ESL_IO_MGMT structures are separated and placed on
213  the free list by calling ::EslSocketIoInit.  The ESL_IO_MGMT structure contains
214  the network layer specific receive completion token and event.  The receive engine
215  is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
216  structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
217
218<code><pre>
219
220         pPort->pRxActive
221                |
222                V
223          +-------------+   +-------------+   +-------------+
224  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
225          +-------------+   +-------------+   +-------------+
226
227          +-------------+   +-------------+   +-------------+
228  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
229          +-------------+   +-------------+   +-------------+
230                ^
231                |
232          pPort->pRxFree
233</pre></code>
234
235  The receive engine is started by calling ::EslSocketRxStart.  Flow control pauses
236  the receive engine by stopping the calls to EslSocketRxStart when the amount of
237  receive data waiting for the application meets or exceeds MAX_RX_DATA.  After
238  the application reads enough data that the amount of buffering drops below this
239  limit, the calls to EslSockeRxStart continue which releases the flow control.
240
241  Receive flow control is applied when the port is created, since no receive
242  operation are pending to the low layer network driver.  The flow control gets
243  released when the low layer network port is configured or the first receive
244  operation is posted.  Flow control remains in the released state until the
245  maximum buffer space is consumed.  During this time, ::EslSocketRxComplete
246  calls ::EslSocketRxStart.  Flow control is applied in EslSocketRxComplete
247  by skipping the call to EslSocketRxStart.  Flow control is eventually
248  released in ::EslSocketReceive when the buffer space drops below the
249  maximum amount causing EslSocketReceive to call EslSocketRxStart.
250
251<code><pre>
252
253                    +------------+   +------------+
254    High     .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
255  Priority   |      +------------+   +------------+
256             |
257             | pRxOobPacketListHead
258       +------------+
259       | ::ESL_SOCKET |
260       +------------+
261             | pRxPacketListHead
262    Low      |
263  Priority   |      +------------+   +------------+   +------------+
264             `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
265                    +------------+   +------------+   +------------+
266
267</pre></code>
268
269  ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
270  and then calls the network layer to start the receive operation.  Upon
271  receive completion, ::EslSocketRxComplete breaks the connection between these
272  structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
273  make token and event available for another receive operation.  EslSocketRxComplete
274  then queues the ESL_PACKET structure (data packet) to either the
275  ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
276  whether urgent or normal data was received.  Finally ::EslSocketRxComplete attempts
277  to start another receive operation.
278
279<code><pre>
280
281  Setup for IP4 and UDP4
282
283      +--------------------+
284      | ESL_IO_MGMT        |
285      |                    |
286      |    +---------------+
287      |    | Token         |
288      |    |        RxData --> NULL
289      +----+---------------+
290         |
291         V
292      +--------------------+
293      | ESL_PACKET         |
294      |                    |
295      |    +---------------+
296      |    |       pRxData --> NULL
297      +----+---------------+
298
299  Completion for IP4 and UDP4
300
301      +--------------------+   +----------------------+
302      | ESL_IO_MGMT        |   |      Data Buffer     |
303      |                    |   |     (Driver owned)   |
304      |    +---------------+   +----------------------+
305      |    | Token         |               ^
306      |    |      Rx Event |               |
307      |    |               |   +----------------------+
308      |    |        RxData --> | EFI_IP4_RECEIVE_DATA |
309      +----+---------------+   |    (Driver owned)    |
310         |                     +----------------------+
311         V                                 ^
312      +--------------------+               .
313      | ESL_PACKET         |               .
314      |                    |               .
315      |    +---------------+               .
316      |    |       pRxData --> NULL  .......
317      +----+---------------+
318
319
320  Setup and completion for TCP4
321
322      +--------------------+   +--------------------------+
323      | ESL_IO_MGMT        |-->| ESL_PACKET               |
324      |                    |   |                          |
325      |    +---------------+   +----------------------+   |
326      |    | Token         |   | EFI_IP4_RECEIVE_DATA |   |
327      |    |        RxData --> |                      |   |
328      |    |               |   +----------------------+---+
329      |    |        Event  |   |       Data Buffer        |
330      +----+---------------+   |                          |
331                               |                          |
332                               +--------------------------+
333
334</pre></code>
335
336  To minimize the number of buffer copies, the data is not copied until the
337  application makes a receive call.  At this point socket performs a single copy
338  in the receive path to move the data from the buffer filled by the network layer
339  into the application's buffer.
340
341  The IP4 and UDP4 drivers go one step further to reduce buffer copies.  They
342  allow the socket layer to hold on to the actual receive buffer until the
343  application has performed a receive operation or closes the socket.  Both
344  of theses operations return the buffer to the lower layer network driver
345  by calling ESL_PROTOCOL_API::pfnPacketFree.
346
347  When a socket application wants to receive data it indirectly calls
348  ::EslSocketReceive to remove data from one of the receive data queues.  This routine
349  removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
350  ESL_SOCKET::pRxPacketListHead and copies the data from the packet
351  into the application's buffer.  For SOCK_STREAM sockets, if the packet
352  contains more data then the ESL_PACKET structures remains at the head of the
353  receive queue for the next application receive
354  operation.  For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
355  structure is removed from the head of the receive queue and any remaining data is
356  discarded as the packet is placed on the free queue.
357
358  During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
359  cancel any pending receive operations.  EslSocketRxCancel calls the network specific
360  cancel routine using ESL_PORT::pfnRxCancel.
361
362
363  \section TransmitEngine Transmit Engine
364
365  Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
366  The buffer exists as an extension to an ESL_PACKET structure and the structure
367  is placed at the end of the transmit queue.
368
369<code><pre>
370
371     *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
372          |
373          V
374        +------------+   +------------+   +------------+
375  Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
376        +------------+   +------------+   +------------+
377                                                     ^
378                                                     |
379     *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
380
381</pre></code>
382
383  There are actually two transmit queues the normal or low priority queue which is
384  the default and the urgent or high priority queue which is addressed by specifying
385  the MSG_OOB flag during the transmit request.  Associated with each queue is a
386  transmit engine which is responsible for sending the data in that queue.
387
388  The transmit engine is the state machine which removes entries from the head
389  of the transmit queue and causes the data to be sent over the network.
390
391<code><pre>
392
393      +--------------------+   +--------------------+
394      | ESL_IO_MGMT        |   | ESL_PACKET         |
395      |                    |   |                    |
396      |    +---------------+   +----------------+   |
397      |    | Token         |   | Buffer Length  |   |
398      |    |        TxData --> | Buffer Address |   |
399      |    |               |   +----------------+---+
400      |    |        Event  |   | Data Buffer        |
401      +----+---------------+   |                    |
402                               +--------------------+
403</pre></code>
404
405  At a high level, the transmit engine uses a couple of data structures
406  to manage the data flow.  The ::ESL_IO_MGMT structures manage the tokens and
407  events for the interface to the UEFI network stack.  The ::ESL_PACKET
408  structures manage the data buffers that get sent.  The transmit
409  engine connects these two structures prior to transmission and disconnects
410  them upon completion.
411
412<code><pre>
413
414         pPort->pTxActive or pTxOobActive
415                |
416                V
417          +-------------+   +-------------+   +-------------+
418  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
419          +-------------+   +-------------+   +-------------+
420
421          +-------------+   +-------------+   +-------------+
422  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
423          +-------------+   +-------------+   +-------------+
424                ^
425                |
426          pPort->pTxFree or pTxOobFree
427
428</pre></code>
429
430  The transmit engine manages multiple transmit operations using the
431  active and free lists shown above.  ::EslSocketPortAllocate allocates the
432  ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
433  This routine places the ESL_IO_MGMT structures on the free list by calling
434  ::EslSocketIoInit.  During their lifetime, the ESL_IO_MGMT structures
435  will move from the free list to the active list and back again.  The
436  active list contains the packets that are actively being processed by
437  the UEFI network stack.  Eventually the ESL_IO_MGMT structures will be
438  removed from the free list and be deallocated by the EslSocketPortClose
439  routine.
440
441  The network specific code calls the ::EslSocketTxStart routine
442  to hand a packet to the network stack.  EslSocketTxStart connects
443  the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
444  and then queues the result to one of the active lists:
445  ESL_PORT::pTxActive or ESL_PORT::pTxOobActive.  The routine then
446  hands the packet to the network stack.
447
448  Upon completion, the network specific TxComplete routine calls
449  ::EslSocketTxComplete to disconnect the transmit packet from the
450  ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
451  ::EslSocketPacketFree.  The routine places the ::ESL_IO_MGMT structure
452  into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
453  EslSocketTxComplete then starts the next transmit operation while
454  the socket is active or calls the ::EslSocketPortCloseTxDone routine
455  when the socket is shutting down.
456
457**/
458
459#include "Socket.h"
460
461
462/** Socket driver connection points
463
464  List the network stack connection points for the socket driver.
465**/
466CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
467  { L"Ip4",
468    &gEfiIp4ServiceBindingProtocolGuid,
469    &gEfiIp4ProtocolGuid,
470    &mEslIp4ServiceGuid,
471    OFFSET_OF ( ESL_LAYER, pIp4List ),
472    4,    //  RX buffers
473    4,    //  TX buffers
474    0 },  //  TX Oob buffers
475  { L"Tcp4",
476    &gEfiTcp4ServiceBindingProtocolGuid,
477    &gEfiTcp4ProtocolGuid,
478    &mEslTcp4ServiceGuid,
479    OFFSET_OF ( ESL_LAYER, pTcp4List ),
480    4,    //  RX buffers
481    4,    //  TX buffers
482    4 },  //  TX Oob buffers
483  { L"Tcp6",
484    &gEfiTcp6ServiceBindingProtocolGuid,
485    &gEfiTcp6ProtocolGuid,
486    &mEslTcp6ServiceGuid,
487    OFFSET_OF ( ESL_LAYER, pTcp6List ),
488    4,    //  RX buffers
489    4,    //  TX buffers
490    4 },  //  TX Oob buffers
491  { L"Udp4",
492    &gEfiUdp4ServiceBindingProtocolGuid,
493    &gEfiUdp4ProtocolGuid,
494    &mEslUdp4ServiceGuid,
495    OFFSET_OF ( ESL_LAYER, pUdp4List ),
496    4,    //  RX buffers
497    4,    //  TX buffers
498    0 },  //  TX Oob buffers
499  { L"Udp6",
500    &gEfiUdp6ServiceBindingProtocolGuid,
501    &gEfiUdp6ProtocolGuid,
502    &mEslUdp6ServiceGuid,
503    OFFSET_OF ( ESL_LAYER, pUdp6List ),
504    4,    //  RX buffers
505    4,    //  TX buffers
506    0 }   //  TX Oob buffers
507};
508
509CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
510
511/// APIs to support the various socket types for the v4 network stack.
512CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {
513  NULL,             //  0
514  &cEslTcp4Api,     //  SOCK_STREAM
515  &cEslUdp4Api,     //  SOCK_DGRAM
516  &cEslIp4Api,      //  SOCK_RAW
517  NULL,             //  SOCK_RDM
518  &cEslTcp4Api      //  SOCK_SEQPACKET
519};
520
521/// Number of entries in the v4 API array ::cEslAfInetApi.
522CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
523
524
525/// APIs to support the various socket types for the v6 network stack.
526CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
527  NULL,             //  0
528  &cEslTcp6Api,     //  SOCK_STREAM
529  &cEslUdp6Api,     //  SOCK_DGRAM
530  NULL,             //  SOCK_RAW
531  NULL,             //  SOCK_RDM
532  &cEslTcp6Api      //  SOCK_SEQPACKET
533};
534
535/// Number of entries in the v6 API array ::cEslAfInet6Api.
536CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
537
538
539/// Global management structure for the socket layer.
540ESL_LAYER mEslLayer;
541
542
543/** Initialize an endpoint for network communication.
544
545  This routine initializes the communication endpoint.
546
547  The ::socket routine calls this routine indirectly to create
548  the communication endpoint.
549
550  @param[in] pSocketProtocol Address of the socket protocol structure.
551  @param[in]  domain   Select the family of protocols for the client or server
552                       application.  See the ::socket documentation for values.
553  @param[in]  type     Specifies how to make the network connection.
554                       See the ::socket documentation for values.
555  @param[in]  protocol Specifies the lower layer protocol to use.
556                       See the ::socket documentation for values.
557  @param[out] pErrno   Address to receive the errno value upon completion.
558
559  @retval EFI_SUCCESS - Socket successfully created
560  @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
561  @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
562  @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
563 **/
564EFI_STATUS
565EslSocket (
566  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
567  IN int domain,
568  IN int type,
569  IN int protocol,
570  IN int * pErrno
571  )
572{
573  CONST ESL_PROTOCOL_API * pApi;
574  CONST ESL_PROTOCOL_API ** ppApiArray;
575  CONST ESL_PROTOCOL_API ** ppApiArrayEnd;
576  int ApiArraySize;
577  ESL_SOCKET * pSocket;
578  EFI_STATUS Status;
579  int errno;
580
581  DBG_ENTER ( );
582
583  //  Locate the socket
584  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
585
586  //  Set the default domain if necessary
587  if ( AF_UNSPEC == domain ) {
588    domain = AF_INET;
589  }
590
591  //  Assume success
592  errno = 0;
593  Status = EFI_SUCCESS;
594
595  //  Use break instead of goto
596  for ( ; ; ) {
597    //  Validate the domain value
598    if (( AF_INET != domain )
599      && ( AF_INET6 != domain )
600      && ( AF_LOCAL != domain )) {
601      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
602                "ERROR - Invalid domain value\r\n" ));
603      Status = EFI_INVALID_PARAMETER;
604      errno = EAFNOSUPPORT;
605      break;
606    }
607
608    //  Determine the protocol APIs
609    ppApiArray = NULL;
610    ApiArraySize = 0;
611    if (( AF_INET == domain )
612      || ( AF_LOCAL == domain )) {
613      ppApiArray = &cEslAfInetApi[0];
614      ApiArraySize = cEslAfInetApiSize;
615    }
616    else {
617      ppApiArray = &cEslAfInet6Api[0];
618      ApiArraySize = cEslAfInet6ApiSize;
619    }
620
621    //  Set the default type if necessary
622    if ( 0 == type ) {
623      type = SOCK_STREAM;
624    }
625
626    //  Validate the type value
627    if (( type >= ApiArraySize )
628      || ( NULL == ppApiArray )
629      || ( NULL == ppApiArray[ type ])) {
630      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
631                "ERROR - Invalid type value\r\n" ));
632      //  The socket type is not supported
633      Status = EFI_INVALID_PARAMETER;
634      errno = EPROTOTYPE;
635      break;
636    }
637
638    //  Set the default protocol if necessary
639    pApi = ppApiArray[ type ];
640    if ( 0 == protocol ) {
641      protocol = pApi->DefaultProtocol;
642    }
643
644    //  Validate the protocol value
645    if (( pApi->DefaultProtocol != protocol )
646      && ( SOCK_RAW != type )) {
647      Status = EFI_INVALID_PARAMETER;
648
649      //  Assume that the driver supports this protocol
650      ppApiArray = &cEslAfInetApi[0];
651      ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];
652      while ( ppApiArrayEnd > ppApiArray ) {
653        pApi = *ppApiArray;
654        if ( protocol == pApi->DefaultProtocol ) {
655          break;
656        }
657        ppApiArray += 1;
658      }
659      if ( ppApiArrayEnd <= ppApiArray ) {
660        //  Verify against the IPv6 table
661        ppApiArray = &cEslAfInet6Api[0];
662        ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];
663        while ( ppApiArrayEnd > ppApiArray ) {
664          pApi = *ppApiArray;
665          if ( protocol == pApi->DefaultProtocol ) {
666            break;
667          }
668          ppApiArray += 1;
669        }
670      }
671      if ( ppApiArrayEnd <= ppApiArray ) {
672        DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
673                  "ERROR - The protocol is not supported!\r\n" ));
674        errno = EPROTONOSUPPORT;
675        break;
676      }
677
678      //  The driver does not support this protocol
679      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
680                "ERROR - The protocol does not support this socket type!\r\n" ));
681      errno = EPROTONOSUPPORT;
682      errno = EPROTOTYPE;
683      break;
684    }
685    //  Save the socket attributes
686    pSocket->pApi = pApi;
687    pSocket->Domain = domain;
688    pSocket->Type = type;
689    pSocket->Protocol = protocol;
690
691    //  Done
692    break;
693  }
694  //  Return the operation status
695  if ( NULL != pErrno ) {
696    *pErrno = errno;
697  }
698  DBG_EXIT_STATUS ( Status );
699  return Status;
700}
701
702
703/** Accept a network connection.
704
705  This routine calls the network specific layer to remove the next
706  connection from the FIFO.
707
708  The ::accept calls this routine to poll for a network
709  connection to the socket.  When a connection is available
710  this routine returns the ::EFI_SOCKET_PROTOCOL structure address
711  associated with the new socket and the remote network address
712  if requested.
713
714  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
715  @param[in]      pSockAddr         Address of a buffer to receive the remote
716                                    network address.
717  @param[in,out]  pSockAddrLength   Length in bytes of the address buffer.
718                                    On output specifies the length of the
719                                    remote network address.
720  @param[out]     ppSocketProtocol  Address of a buffer to receive the
721                                    ::EFI_SOCKET_PROTOCOL instance
722                                    associated with the new socket.
723  @param[out]     pErrno            Address to receive the errno value upon completion.
724
725  @retval EFI_SUCCESS   New connection successfully created
726  @retval EFI_NOT_READY No connection is available
727 **/
728EFI_STATUS
729EslSocketAccept (
730  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
731  IN struct sockaddr * pSockAddr,
732  IN OUT socklen_t * pSockAddrLength,
733  IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,
734  IN int * pErrno
735  )
736{
737  ESL_SOCKET * pNewSocket;
738  ESL_SOCKET * pSocket;
739  EFI_STATUS Status;
740  EFI_TPL TplPrevious;
741
742  DBG_ENTER ( );
743
744  //
745  //  Assume success
746  //
747  Status = EFI_SUCCESS;
748
749  //
750  //  Validate the socket
751  //
752  pSocket = NULL;
753  pNewSocket = NULL;
754  if ( NULL != pSocketProtocol ) {
755    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
756
757    //
758    //  Verify the API
759    //
760    if ( NULL == pSocket->pApi->pfnAccept ) {
761      Status = EFI_UNSUPPORTED;
762      pSocket->errno = ENOTSUP;
763    }
764    else {
765      //
766      //  Validate the sockaddr
767      //
768      if (( NULL != pSockAddr )
769        && ( NULL == pSockAddrLength )) {
770        DEBUG (( DEBUG_ACCEPT,
771                  "ERROR - pSockAddr is NULL!\r\n" ));
772        Status = EFI_INVALID_PARAMETER;
773        pSocket->errno = EFAULT;
774      }
775      else {
776        //
777        //  Synchronize with the socket layer
778        //
779        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
780
781        //
782        //  Verify that the socket is in the listen state
783        //
784        if ( SOCKET_STATE_LISTENING != pSocket->State ) {
785          DEBUG (( DEBUG_ACCEPT,
786                    "ERROR - Socket is not listening!\r\n" ));
787          if ( NULL == pSocket->pApi->pfnAccept ) {
788            //
789            //  Socket does not support listen
790            //
791            pSocket->errno = EOPNOTSUPP;
792            Status = EFI_UNSUPPORTED;
793          }
794          else {
795            //
796            //  Socket supports listen, but not in listen state
797            //
798            pSocket->errno = EINVAL;
799            Status = EFI_NOT_STARTED;
800          }
801        }
802        else {
803          //
804          //  Determine if a socket is available
805          //
806          if ( 0 == pSocket->FifoDepth ) {
807            //
808            //  No connections available
809            //  Determine if any ports are available
810            //
811            if ( NULL == pSocket->pPortList ) {
812              //
813              //  No ports available
814              //
815              Status = EFI_DEVICE_ERROR;
816              pSocket->errno = EINVAL;
817
818              //
819              //  Update the socket state
820              //
821              pSocket->State = SOCKET_STATE_NO_PORTS;
822            }
823            else {
824              //
825              //  Ports are available
826              //  No connection requests at this time
827              //
828              Status = EFI_NOT_READY;
829              pSocket->errno = EAGAIN;
830            }
831          }
832          else {
833
834            //
835            //  Attempt to accept the connection and
836            //  get the remote network address
837            //
838            pNewSocket = pSocket->pFifoHead;
839            ASSERT ( NULL != pNewSocket );
840            Status = pSocket->pApi->pfnAccept ( pNewSocket,
841                                                pSockAddr,
842                                                pSockAddrLength );
843            if ( !EFI_ERROR ( Status )) {
844              //
845              //  Remove the new socket from the list
846              //
847              pSocket->pFifoHead = pNewSocket->pNextConnection;
848              if ( NULL == pSocket->pFifoHead ) {
849                pSocket->pFifoTail = NULL;
850              }
851
852              //
853              //  Account for this socket
854              //
855              pSocket->FifoDepth -= 1;
856
857              //
858              //  Update the new socket's state
859              //
860              pNewSocket->State = SOCKET_STATE_CONNECTED;
861              pNewSocket->bConfigured = TRUE;
862              DEBUG (( DEBUG_ACCEPT,
863                        "0x%08x: Socket connected\r\n",
864                        pNewSocket ));
865            }
866          }
867        }
868
869        //
870        //  Release the socket layer synchronization
871        //
872        RESTORE_TPL ( TplPrevious );
873      }
874    }
875  }
876
877  //
878  //  Return the new socket
879  //
880  if (( NULL != ppSocketProtocol )
881    && ( NULL != pNewSocket )) {
882    *ppSocketProtocol = &pNewSocket->SocketProtocol;
883  }
884
885  //
886  //  Return the operation status
887  //
888  if ( NULL != pErrno ) {
889    if ( NULL != pSocket ) {
890      *pErrno = pSocket->errno;
891    }
892    else {
893      Status = EFI_INVALID_PARAMETER;
894      *pErrno = ENOTSOCK;
895    }
896  }
897  DBG_EXIT_STATUS ( Status );
898  return Status;
899}
900
901
902/** Allocate and initialize a ESL_SOCKET structure.
903
904  This support function allocates an ::ESL_SOCKET structure
905  and installs a protocol on ChildHandle.  If pChildHandle is a
906  pointer to NULL, then a new handle is created and returned in
907  pChildHandle.  If pChildHandle is not a pointer to NULL, then
908  the protocol installs on the existing pChildHandle.
909
910  @param[in,out]  pChildHandle  Pointer to the handle of the child to create.
911                                If it is NULL, then a new handle is created.
912                                If it is a pointer to an existing UEFI handle,
913                                then the protocol is added to the existing UEFI
914                                handle.
915  @param[in]      DebugFlags    Flags for debug messages
916  @param[in,out]  ppSocket      The buffer to receive an ::ESL_SOCKET structure address.
917
918  @retval EFI_SUCCESS           The protocol was added to ChildHandle.
919  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
920  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
921                                the child
922  @retval other                 The child handle was not created
923**/
924EFI_STATUS
925EFIAPI
926EslSocketAllocate (
927  IN OUT EFI_HANDLE * pChildHandle,
928  IN     UINTN DebugFlags,
929  IN OUT ESL_SOCKET ** ppSocket
930  )
931{
932  UINTN LengthInBytes;
933  ESL_LAYER * pLayer;
934  ESL_SOCKET * pSocket;
935  EFI_STATUS Status;
936  EFI_TPL TplPrevious;
937
938  DBG_ENTER ( );
939
940  //
941  //  Create a socket structure
942  //
943  LengthInBytes = sizeof ( *pSocket );
944  pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );
945  if ( NULL != pSocket ) {
946    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
947              "0x%08x: Allocate pSocket, %d bytes\r\n",
948              pSocket,
949              LengthInBytes ));
950
951    //
952    //  Initialize the socket protocol
953    //
954    pSocket->Signature = SOCKET_SIGNATURE;
955    pSocket->SocketProtocol.pfnAccept = EslSocketAccept;
956    pSocket->SocketProtocol.pfnBind = EslSocketBind;
957    pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;
958    pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;
959    pSocket->SocketProtocol.pfnConnect = EslSocketConnect;
960    pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;
961    pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;
962    pSocket->SocketProtocol.pfnListen = EslSocketListen;
963    pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;
964    pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;
965    pSocket->SocketProtocol.pfnPoll = EslSocketPoll;
966    pSocket->SocketProtocol.pfnReceive = EslSocketReceive;
967    pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;
968    pSocket->SocketProtocol.pfnSocket = EslSocket;
969    pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;
970
971    pSocket->MaxRxBuf = MAX_RX_DATA;
972    pSocket->MaxTxBuf = MAX_TX_DATA;
973
974    //
975    //  Install the socket protocol on the specified handle
976    //
977    Status = gBS->InstallMultipleProtocolInterfaces (
978                    pChildHandle,
979                    &gEfiSocketProtocolGuid,
980                    &pSocket->SocketProtocol,
981                    NULL
982                    );
983    if ( !EFI_ERROR ( Status )) {
984      DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
985                "Installed: gEfiSocketProtocolGuid on   0x%08x\r\n",
986                *pChildHandle ));
987      pSocket->SocketProtocol.SocketHandle = *pChildHandle;
988
989      //
990      //  Synchronize with the socket layer
991      //
992      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
993
994      //
995      //  Add this socket to the list
996      //
997      pLayer = &mEslLayer;
998      pSocket->pNext = pLayer->pSocketList;
999      pLayer->pSocketList = pSocket;
1000
1001      //
1002      //  Release the socket layer synchronization
1003      //
1004      RESTORE_TPL ( TplPrevious );
1005
1006      //
1007      //  Return the socket structure address
1008      //
1009      *ppSocket = pSocket;
1010    }
1011    else {
1012      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
1013                "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1014                *pChildHandle,
1015                Status ));
1016    }
1017
1018    //
1019    //  Release the socket if necessary
1020    //
1021    if ( EFI_ERROR ( Status )) {
1022      gBS->FreePool ( pSocket );
1023      DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
1024                "0x%08x: Free pSocket, %d bytes\r\n",
1025                pSocket,
1026                sizeof ( *pSocket )));
1027      pSocket = NULL;
1028    }
1029  }
1030  else {
1031    Status = EFI_OUT_OF_RESOURCES;
1032  }
1033
1034  //
1035  //  Return the operation status
1036  //
1037  DBG_EXIT_STATUS ( Status );
1038  return Status;
1039}
1040
1041
1042/** Bind a name to a socket.
1043
1044  This routine calls the network specific layer to save the network
1045  address of the local connection point.
1046
1047  The ::bind routine calls this routine to connect a name
1048  (network address and port) to a socket on the local machine.
1049
1050  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1051  @param[in]  pSockAddr       Address of a sockaddr structure that contains the
1052                              connection point on the local machine.  An IPv4 address
1053                              of INADDR_ANY specifies that the connection is made to
1054                              all of the network stacks on the platform.  Specifying a
1055                              specific IPv4 address restricts the connection to the
1056                              network stack supporting that address.  Specifying zero
1057                              for the port causes the network layer to assign a port
1058                              number from the dynamic range.  Specifying a specific
1059                              port number causes the network layer to use that port.
1060  @param[in]  SockAddrLength  Specifies the length in bytes of the sockaddr structure.
1061  @param[out] pErrno          Address to receive the errno value upon completion.
1062
1063  @retval EFI_SUCCESS - Socket successfully created
1064**/
1065EFI_STATUS
1066EslSocketBind (
1067  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1068  IN CONST struct sockaddr * pSockAddr,
1069  IN socklen_t SockAddrLength,
1070  OUT int * pErrno
1071  )
1072{
1073  EFI_HANDLE ChildHandle;
1074  UINT8 * pBuffer;
1075  ESL_PORT * pPort;
1076  ESL_SERVICE ** ppServiceListHead;
1077  ESL_SOCKET * pSocket;
1078  ESL_SERVICE * pService;
1079  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
1080  EFI_STATUS Status;
1081  EFI_TPL TplPrevious;
1082
1083  DBG_ENTER ( );
1084
1085  //
1086  //  Assume success
1087  //
1088  Status = EFI_SUCCESS;
1089
1090  //
1091  //  Validate the socket
1092  //
1093  pSocket = NULL;
1094  if ( NULL != pSocketProtocol ) {
1095    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1096
1097    //
1098    //  Validate the structure pointer
1099    //
1100    pSocket->errno = 0;
1101    if ( NULL == pSockAddr ) {
1102      DEBUG (( DEBUG_BIND,
1103                "ERROR - pSockAddr is NULL!\r\n" ));
1104      Status = EFI_INVALID_PARAMETER;
1105      pSocket->errno = EFAULT;
1106    }
1107
1108    //
1109    //  Validate the local address length
1110    //
1111    else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {
1112      DEBUG (( DEBUG_BIND,
1113                "ERROR - Invalid bind name length: %d\r\n",
1114                SockAddrLength ));
1115      Status = EFI_INVALID_PARAMETER;
1116      pSocket->errno = EINVAL;
1117    }
1118
1119    //
1120    //  Validate the shutdown state
1121    //
1122    else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
1123      DEBUG (( DEBUG_BIND,
1124                "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1125                pSocket ));
1126      pSocket->errno = EINVAL;
1127      Status = EFI_INVALID_PARAMETER;
1128    }
1129
1130    //
1131    //  Verify the socket state
1132    //
1133    else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {
1134      DEBUG (( DEBUG_BIND,
1135                "ERROR - The socket 0x%08x is already configured!\r\n",
1136                pSocket ));
1137      pSocket->errno = EINVAL;
1138      Status = EFI_ALREADY_STARTED;
1139    }
1140    else {
1141      //
1142      //  Synchronize with the socket layer
1143      //
1144      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1145
1146      //
1147      //  Assume no ports are available
1148      //
1149      pSocket->errno = EADDRNOTAVAIL;
1150      Status = EFI_INVALID_PARAMETER;
1151
1152      //
1153      //  Walk the list of services
1154      //
1155      pBuffer = (UINT8 *)&mEslLayer;
1156      pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];
1157      ppServiceListHead = (ESL_SERVICE **)pBuffer;
1158      pService = *ppServiceListHead;
1159      while ( NULL != pService ) {
1160        //
1161        //  Create the port
1162        //
1163        pServiceBinding = pService->pServiceBinding;
1164        ChildHandle = NULL;
1165        Status = pServiceBinding->CreateChild ( pServiceBinding,
1166                                                &ChildHandle );
1167        if ( !EFI_ERROR ( Status )) {
1168          DEBUG (( DEBUG_BIND | DEBUG_POOL,
1169                    "0x%08x: %s port handle created\r\n",
1170                    ChildHandle,
1171                    pService->pSocketBinding->pName ));
1172
1173          //
1174          //  Open the port
1175          //
1176          Status = EslSocketPortAllocate ( pSocket,
1177                                           pService,
1178                                           ChildHandle,
1179                                           pSockAddr,
1180                                           TRUE,
1181                                           DEBUG_BIND,
1182                                           &pPort );
1183        }
1184        else {
1185          DEBUG (( DEBUG_BIND | DEBUG_POOL,
1186                    "ERROR - Failed to open %s port handle, Status: %r\r\n",
1187                    pService->pSocketBinding->pName,
1188                    Status ));
1189        }
1190
1191        //
1192        //  Set the next service
1193        //
1194        pService = pService->pNext;
1195      }
1196
1197      //
1198      //  Verify that at least one network connection was found
1199      //
1200      if ( NULL != pSocket->pPortList ) {
1201        Status = EFI_SUCCESS;
1202      }
1203      else {
1204        if ( EADDRNOTAVAIL == pSocket->errno ) {
1205          DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
1206                    "ERROR - Socket address is not available!\r\n" ));
1207        }
1208        if ( EADDRINUSE == pSocket->errno ) {
1209          DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
1210                    "ERROR - Socket address is in use!\r\n" ));
1211        }
1212        Status = EFI_INVALID_PARAMETER;
1213      }
1214
1215      //
1216      //  Mark this socket as bound if successful
1217      //
1218      if ( !EFI_ERROR ( Status )) {
1219        pSocket->State = SOCKET_STATE_BOUND;
1220        pSocket->errno = 0;
1221      }
1222
1223      //
1224      //  Release the socket layer synchronization
1225      //
1226      RESTORE_TPL ( TplPrevious );
1227    }
1228  }
1229
1230  //
1231  //  Return the operation status
1232  //
1233  if ( NULL != pErrno ) {
1234    if ( NULL != pSocket ) {
1235      *pErrno = pSocket->errno;
1236    }
1237    else {
1238      Status = EFI_INVALID_PARAMETER;
1239      *pErrno = ENOTSOCK;
1240    }
1241  }
1242  DBG_EXIT_STATUS ( Status );
1243  return Status;
1244}
1245
1246
1247/** Test the bind configuration.
1248
1249  @param[in] pPort        Address of the ::ESL_PORT structure.
1250  @param[in] ErrnoValue   errno value if test fails
1251
1252  @retval EFI_SUCCESS   The connection was successfully established.
1253  @retval Others        The connection attempt failed.
1254**/
1255EFI_STATUS
1256EslSocketBindTest (
1257  IN ESL_PORT * pPort,
1258  IN int ErrnoValue
1259  )
1260{
1261  UINT8 * pBuffer;
1262  VOID * pConfigData;
1263  EFI_STATUS Status;
1264
1265  DBG_ENTER ( );
1266
1267  //
1268  //  Locate the configuration data
1269  //
1270  pBuffer = (UINT8 *)pPort;
1271  pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];
1272  pConfigData = (VOID *)pBuffer;
1273
1274  //
1275  //  Validate that the port is connected
1276  //
1277  Status = pPort->pSocket->pApi->pfnVerifyLocalIpAddress ( pPort, pBuffer );
1278  if ( EFI_ERROR ( Status )) {
1279    DEBUG (( DEBUG_WARN | DEBUG_BIND,
1280              "WARNING - Port 0x%08x invalid IP address: %r\r\n",
1281              pPort,
1282              Status ));
1283    pPort->pSocket->errno = ErrnoValue;
1284  }
1285  else {
1286    //
1287    //  Attempt to use this configuration
1288    //
1289    Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );
1290    if ( EFI_ERROR ( Status )) {
1291      DEBUG (( DEBUG_WARN | DEBUG_BIND,
1292                "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1293                pPort,
1294                Status ));
1295      pPort->pSocket->errno = ErrnoValue;
1296    }
1297    else {
1298      //
1299      //  Reset the port
1300      //
1301      Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );
1302      if ( EFI_ERROR ( Status )) {
1303        DEBUG (( DEBUG_ERROR | DEBUG_BIND,
1304                  "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1305                  pPort,
1306                  Status ));
1307        ASSERT ( EFI_SUCCESS == Status );
1308      }
1309    }
1310  }
1311
1312  //
1313  //  Return the operation status
1314  //
1315  DBG_EXIT_STATUS ( Status );
1316  return Status;
1317}
1318
1319
1320/** Determine if the socket is closed.
1321
1322  This routine checks the state of the socket to determine if
1323  the network specific layer has completed the close operation.
1324
1325  The ::close routine polls this routine to determine when the
1326  close operation is complete.  The close operation needs to
1327  reverse the operations of the ::EslSocketAllocate routine.
1328
1329  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1330  @param[out] pErrno          Address to receive the errno value upon completion.
1331
1332  @retval EFI_SUCCESS     Socket successfully closed
1333  @retval EFI_NOT_READY   Close still in progress
1334  @retval EFI_ALREADY     Close operation already in progress
1335  @retval Other           Failed to close the socket
1336**/
1337EFI_STATUS
1338EslSocketClosePoll (
1339  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1340  IN int * pErrno
1341  )
1342{
1343  int errno;
1344  ESL_LAYER * pLayer;
1345  ESL_SOCKET * pNextSocket;
1346  ESL_SOCKET * pSocket;
1347  EFI_STATUS Status;
1348  EFI_TPL TplPrevious;
1349
1350  DBG_ENTER ( );
1351
1352  //
1353  //  Assume success
1354  //
1355  errno = 0;
1356  Status = EFI_SUCCESS;
1357
1358  //
1359  //  Synchronize with the socket layer
1360  //
1361  RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1362
1363  //
1364  //  Locate the socket
1365  //
1366  pLayer = &mEslLayer;
1367  pNextSocket = pLayer->pSocketList;
1368  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1369  while ( NULL != pNextSocket ) {
1370    if ( pNextSocket == pSocket ) {
1371      //
1372      //  Determine if the socket is in the closing state
1373      //
1374      if ( SOCKET_STATE_CLOSED == pSocket->State ) {
1375        //
1376        //  Walk the list of ports
1377        //
1378        if ( NULL == pSocket->pPortList ) {
1379          //
1380          //  All the ports are closed
1381          //  Close the WaitAccept event if necessary
1382          //
1383          if ( NULL != pSocket->WaitAccept ) {
1384            Status = gBS->CloseEvent ( pSocket->WaitAccept );
1385            if ( !EFI_ERROR ( Status )) {
1386              DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
1387                        "0x%08x: Closed WaitAccept event\r\n",
1388                        pSocket->WaitAccept ));
1389              //
1390              //  Return the transmit status
1391              //
1392              Status = pSocket->TxError;
1393              if ( EFI_ERROR ( Status )) {
1394                pSocket->errno = EIO;
1395              }
1396            }
1397            else {
1398              DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
1399                        "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1400                        Status ));
1401              ASSERT ( EFI_SUCCESS == Status );
1402            }
1403          }
1404        }
1405        else {
1406          //
1407          //  At least one port is still open
1408          //
1409          Status = EFI_NOT_READY;
1410          errno = EAGAIN;
1411        }
1412      }
1413      else {
1414        //
1415        //  SocketCloseStart was not called
1416        //
1417        Status = EFI_NOT_STARTED;
1418        errno = EPERM;
1419      }
1420      break;
1421    }
1422
1423    //
1424    //  Set the next socket
1425    //
1426    pNextSocket = pNextSocket->pNext;
1427  }
1428
1429  //
1430  //  Handle the error case where the socket was already closed
1431  //
1432  if ( NULL == pSocket ) {
1433    //
1434    //  Socket not found
1435    //
1436    Status = EFI_NOT_FOUND;
1437    errno = ENOTSOCK;
1438  }
1439
1440  //
1441  //  Release the socket layer synchronization
1442  //
1443  RESTORE_TPL ( TplPrevious );
1444
1445  //
1446  //  Return the operation status
1447  //
1448  if ( NULL != pErrno ) {
1449    *pErrno = errno;
1450  }
1451  DBG_EXIT_STATUS ( Status );
1452  return Status;
1453}
1454
1455
1456/** Start the close operation on the socket.
1457
1458  This routine calls the network specific layer to initiate the
1459  close state machine.  This routine then calls the network
1460  specific layer to determine if the close state machine has gone
1461  to completion.  The result from this poll is returned to the
1462  caller.
1463
1464  The ::close routine calls this routine to start the close
1465  operation which reverses the operations of the
1466  ::EslSocketAllocate routine.  The close routine then polls
1467  the ::EslSocketClosePoll routine to determine when the
1468  socket is closed.
1469
1470  @param[in] pSocketProtocol  Address of an ::EFI_SOCKET_PROTOCOL structure.
1471  @param[in] bCloseNow        Boolean to control close behavior
1472  @param[out] pErrno          Address to receive the errno value upon completion.
1473
1474  @retval EFI_SUCCESS     Socket successfully closed
1475  @retval EFI_NOT_READY   Close still in progress
1476  @retval EFI_ALREADY     Close operation already in progress
1477  @retval Other           Failed to close the socket
1478**/
1479EFI_STATUS
1480EslSocketCloseStart (
1481  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1482  IN BOOLEAN bCloseNow,
1483  IN int * pErrno
1484  )
1485{
1486  int errno;
1487  ESL_PORT * pNextPort;
1488  ESL_PORT * pPort;
1489  ESL_SOCKET * pSocket;
1490  EFI_STATUS Status;
1491  EFI_TPL TplPrevious;
1492
1493  DBG_ENTER ( );
1494
1495  //
1496  //  Assume success
1497  //
1498  Status = EFI_SUCCESS;
1499  errno = 0;
1500
1501  //
1502  //  Synchronize with the socket layer
1503  //
1504  RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1505
1506  //
1507  //  Determine if the socket is already closed
1508  //
1509  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1510  if ( SOCKET_STATE_CLOSED > pSocket->State ) {
1511    //
1512    //  Update the socket state
1513    //
1514    pSocket->State = SOCKET_STATE_CLOSED;
1515
1516    //
1517    //  Walk the list of ports
1518    //
1519    pPort = pSocket->pPortList;
1520    while ( NULL != pPort ) {
1521      //
1522      //  Start closing the ports
1523      //
1524      pNextPort = pPort->pLinkSocket;
1525      Status = EslSocketPortCloseStart ( pPort,
1526                                         bCloseNow,
1527                                         DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
1528      if (( EFI_SUCCESS != Status )
1529        && ( EFI_NOT_READY != Status )) {
1530        errno = EIO;
1531        break;
1532      }
1533
1534      //
1535      //  Set the next port
1536      //
1537      pPort = pNextPort;
1538    }
1539
1540    //
1541    //  Attempt to finish closing the socket
1542    //
1543    if ( NULL == pPort ) {
1544      Status = EslSocketClosePoll ( pSocketProtocol, &errno );
1545    }
1546  }
1547  else {
1548    Status = EFI_NOT_READY;
1549    errno = EAGAIN;
1550  }
1551
1552  //
1553  //  Release the socket layer synchronization
1554  //
1555  RESTORE_TPL ( TplPrevious );
1556
1557  //
1558  //  Return the operation status
1559  //
1560  if ( NULL != pErrno ) {
1561    *pErrno = errno;
1562  }
1563  DBG_EXIT_STATUS ( Status );
1564  return Status;
1565}
1566
1567
1568/** Connect to a remote system via the network.
1569
1570  This routine calls the network specific layer to establish
1571  the remote system address and establish the connection to
1572  the remote system.
1573
1574  The ::connect routine calls this routine to establish a
1575  connection with the specified remote system.  This routine
1576  is designed to be polled by the connect routine for completion
1577  of the network connection.
1578
1579  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1580  @param[in]  pSockAddr       Network address of the remote system.
1581  @param[in]  SockAddrLength  Length in bytes of the network address.
1582  @param[out] pErrno          Address to receive the errno value upon completion.
1583
1584  @retval EFI_SUCCESS     The connection was successfully established.
1585  @retval EFI_NOT_READY   The connection is in progress, call this routine again.
1586  @retval Others          The connection attempt failed.
1587 **/
1588EFI_STATUS
1589EslSocketConnect (
1590  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1591  IN const struct sockaddr * pSockAddr,
1592  IN socklen_t SockAddrLength,
1593  IN int * pErrno
1594  )
1595{
1596  struct sockaddr_in6 LocalAddress;
1597  ESL_PORT * pPort;
1598  ESL_SOCKET * pSocket;
1599  EFI_STATUS Status;
1600  EFI_TPL TplPrevious;
1601
1602  DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));
1603
1604  //
1605  //  Assume success
1606  //
1607  Status = EFI_SUCCESS;
1608
1609  //
1610  //  Validate the socket
1611  //
1612  pSocket = NULL;
1613  if ( NULL != pSocketProtocol ) {
1614    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1615
1616    //
1617    //  Validate the name length
1618    //
1619    if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {
1620      DEBUG (( DEBUG_CONNECT,
1621                "ERROR - Invalid bind name length: %d\r\n",
1622                SockAddrLength ));
1623      Status = EFI_INVALID_PARAMETER;
1624      pSocket->errno = EINVAL;
1625    }
1626    else {
1627      //
1628      //  Assume success
1629      //
1630      pSocket->errno = 0;
1631
1632      //
1633      //  Synchronize with the socket layer
1634      //
1635      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1636
1637      //
1638      //  Validate the socket state
1639      //
1640      switch ( pSocket->State ) {
1641      default:
1642        //
1643        //  Wrong socket state
1644        //
1645        pSocket->errno = EIO;
1646        Status = EFI_DEVICE_ERROR;
1647        break;
1648
1649      case SOCKET_STATE_NOT_CONFIGURED:
1650      case SOCKET_STATE_BOUND:
1651        //
1652        //  Validate the address length
1653        //
1654        if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {
1655          //
1656          //  Verify the API
1657          //
1658          if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {
1659            //
1660            //  Already connected
1661            //
1662            pSocket->errno = ENOTSUP;
1663            Status = EFI_UNSUPPORTED;
1664          }
1665          else {
1666            //
1667            //  Determine if BIND was already called
1668            //
1669            if ( NULL == pSocket->pPortList ) {
1670              //
1671              //  Allow any local port
1672              //
1673              ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
1674              LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;
1675              LocalAddress.sin6_family = pSocket->pApi->AddressFamily;
1676              Status = EslSocketBind ( &pSocket->SocketProtocol,
1677                                       (struct sockaddr *)&LocalAddress,
1678                                       LocalAddress.sin6_len,
1679                                       &pSocket->errno );
1680            }
1681            if ( NULL != pSocket->pPortList ) {
1682              //
1683              //  Walk the list of ports
1684              //
1685              pPort = pSocket->pPortList;
1686              while ( NULL != pPort ) {
1687                //
1688                //  Set the remote address
1689                //
1690                Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,
1691                                                           pSockAddr,
1692                                                           SockAddrLength );
1693                if ( EFI_ERROR ( Status )) {
1694                  break;
1695                }
1696
1697                //
1698                //  Set the next port
1699                //
1700                pPort = pPort->pLinkSocket;
1701              }
1702
1703              //
1704              //  Verify the API
1705              //
1706              if (( !EFI_ERROR ( Status ))
1707                && ( NULL != pSocket->pApi->pfnConnectStart )) {
1708                //
1709                //  Initiate the connection with the remote system
1710                //
1711                Status = pSocket->pApi->pfnConnectStart ( pSocket );
1712
1713                //
1714                //  Set the next state if connecting
1715                //
1716                if ( EFI_NOT_READY == Status ) {
1717                  pSocket->State = SOCKET_STATE_CONNECTING;
1718                }
1719              }
1720            }
1721          }
1722        }
1723        else {
1724          DEBUG (( DEBUG_CONNECT,
1725                    "ERROR - Invalid address length: %d\r\n",
1726                    SockAddrLength ));
1727          Status = EFI_INVALID_PARAMETER;
1728          pSocket->errno = EINVAL;
1729        }
1730        break;
1731
1732      case SOCKET_STATE_CONNECTING:
1733        //
1734        //  Poll the network adapter
1735        //
1736        EslSocketRxPoll ( pSocket );
1737
1738        //
1739        //  Poll for connection completion
1740        //
1741        if ( NULL == pSocket->pApi->pfnConnectPoll ) {
1742          //
1743          //  Already connected
1744          //
1745          pSocket->errno = EISCONN;
1746          Status = EFI_ALREADY_STARTED;
1747        }
1748        else {
1749          Status = pSocket->pApi->pfnConnectPoll ( pSocket );
1750
1751          //
1752          //  Set the next state if connected
1753          //
1754          if ( EFI_NOT_READY != Status ) {
1755            if ( EFI_ERROR ( Status )) {
1756              pSocket->State = SOCKET_STATE_BOUND;
1757            }
1758          }
1759        }
1760        break;
1761
1762      case SOCKET_STATE_CONNECTED:
1763        //
1764        //  Connected
1765        //
1766        Status = EFI_SUCCESS;
1767        break;
1768      }
1769
1770      //
1771      //  Release the socket layer synchronization
1772      //
1773      RESTORE_TPL ( TplPrevious );
1774    }
1775  }
1776
1777  //
1778  //  Return the operation status
1779  //
1780  if ( NULL != pErrno ) {
1781    if ( NULL != pSocket ) {
1782      *pErrno = pSocket->errno;
1783    }
1784    else {
1785      //
1786      //  Bad socket protocol
1787      //
1788      DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
1789                "ERROR - pSocketProtocol invalid!\r\n" ));
1790      Status = EFI_INVALID_PARAMETER;
1791      *pErrno = ENOTSOCK;
1792    }
1793  }
1794
1795  //
1796  //  Return the operation status
1797  //
1798  DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));
1799  return Status;
1800}
1801
1802
1803/** Copy a fragmented buffer into a destination buffer.
1804
1805  This support routine copies a fragmented buffer to the caller specified buffer.
1806
1807  This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1808
1809  @param[in]  FragmentCount   Number of fragments in the table
1810  @param[in]  pFragmentTable  Address of an EFI_IP4_FRAGMENT_DATA structure
1811  @param[in]  BufferLength    Length of the the buffer
1812  @param[in]  pBuffer         Address of a buffer to receive the data.
1813  @param[in]  pDataLength     Number of received data bytes in the buffer.
1814
1815  @return   Returns the address of the next free byte in the buffer.
1816**/
1817UINT8 *
1818EslSocketCopyFragmentedBuffer (
1819  IN UINT32 FragmentCount,
1820  IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
1821  IN size_t BufferLength,
1822  IN UINT8 * pBuffer,
1823  OUT size_t * pDataLength
1824  )
1825{
1826  size_t BytesToCopy;
1827  UINT32 Fragment;
1828  UINT8 * pBufferEnd;
1829  UINT8 * pData;
1830
1831  DBG_ENTER ( );
1832
1833  //
1834  //  Validate the IP and UDP structures are identical
1835  //
1836  ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
1837           == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
1838  ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
1839           == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
1840
1841  //
1842  //  Copy the received data
1843  //
1844  Fragment = 0;
1845  pBufferEnd = &pBuffer [ BufferLength ];
1846  while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
1847    //
1848    //  Determine the amount of received data
1849    //
1850    pData = pFragmentTable[Fragment].FragmentBuffer;
1851    BytesToCopy = pFragmentTable[Fragment].FragmentLength;
1852    if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
1853      BytesToCopy = pBufferEnd - pBuffer;
1854    }
1855
1856    //
1857    //  Move the data into the buffer
1858    //
1859    DEBUG (( DEBUG_RX,
1860              "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1861              pData,
1862              pBuffer,
1863              BytesToCopy ));
1864    CopyMem ( pBuffer, pData, BytesToCopy );
1865    pBuffer += BytesToCopy;
1866    Fragment += 1;
1867  }
1868
1869  //
1870  //  Return the data length and the buffer address
1871  //
1872  *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
1873  DBG_EXIT_HEX ( pBuffer );
1874  return pBuffer;
1875}
1876
1877
1878/** Free the socket.
1879
1880  This routine frees the socket structure and handle resources.
1881
1882  The ::close routine calls EslServiceFreeProtocol which then calls
1883  this routine to free the socket context structure and close the
1884  handle.
1885
1886  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1887  @param[out] pErrno          Address to receive the errno value upon completion.
1888
1889  @retval EFI_SUCCESS   The socket resources were returned successfully.
1890**/
1891EFI_STATUS
1892EslSocketFree (
1893  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1894  IN int * pErrno
1895  )
1896{
1897  EFI_HANDLE ChildHandle;
1898  int errno;
1899  ESL_LAYER * pLayer;
1900  ESL_SOCKET * pSocket;
1901  ESL_SOCKET * pSocketPrevious;
1902  EFI_STATUS Status;
1903  EFI_TPL TplPrevious;
1904
1905  DBG_ENTER ( );
1906
1907  //
1908  //  Assume failure
1909  //
1910  errno = EIO;
1911  pSocket = NULL;
1912  Status = EFI_INVALID_PARAMETER;
1913
1914  //
1915  //  Validate the socket
1916  //
1917  pLayer = &mEslLayer;
1918  if ( NULL != pSocketProtocol ) {
1919    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1920
1921    //
1922    //  Synchronize with the socket layer
1923    //
1924    RAISE_TPL ( TplPrevious, TPL_SOCKETS );
1925
1926    //
1927    //  Walk the socket list
1928    //
1929    pSocketPrevious = pLayer->pSocketList;
1930    if ( NULL != pSocketPrevious ) {
1931      if ( pSocket == pSocketPrevious ) {
1932        //
1933        //  Remove the socket from the head of the list
1934        //
1935        pLayer->pSocketList = pSocket->pNext;
1936      }
1937      else {
1938        //
1939        //  Find the socket in the middle of the list
1940        //
1941        while (( NULL != pSocketPrevious )
1942          && ( pSocket != pSocketPrevious->pNext )) {
1943          //
1944          //  Set the next socket
1945          //
1946          pSocketPrevious = pSocketPrevious->pNext;
1947        }
1948        if ( NULL != pSocketPrevious ) {
1949          //
1950          //  Remove the socket from the middle of the list
1951          //
1952          pSocketPrevious = pSocket->pNext;
1953        }
1954      }
1955    }
1956    else {
1957      DEBUG (( DEBUG_ERROR | DEBUG_POOL,
1958                "ERROR - Socket list is empty!\r\n" ));
1959    }
1960
1961    //
1962    //  Release the socket layer synchronization
1963    //
1964    RESTORE_TPL ( TplPrevious );
1965
1966    //
1967    //  Determine if the socket was found
1968    //
1969    if ( NULL != pSocketPrevious ) {
1970      pSocket->pNext = NULL;
1971
1972      //
1973      //  Remove the socket protocol
1974      //
1975      ChildHandle = pSocket->SocketProtocol.SocketHandle;
1976      Status = gBS->UninstallMultipleProtocolInterfaces (
1977                ChildHandle,
1978                &gEfiSocketProtocolGuid,
1979                &pSocket->SocketProtocol,
1980                NULL );
1981      if ( !EFI_ERROR ( Status )) {
1982        DEBUG (( DEBUG_POOL | DEBUG_INFO,
1983                    "Removed:   gEfiSocketProtocolGuid from 0x%08x\r\n",
1984                    ChildHandle ));
1985
1986        //
1987        //  Free the socket structure
1988        //
1989        Status = gBS->FreePool ( pSocket );
1990        if ( !EFI_ERROR ( Status )) {
1991          DEBUG (( DEBUG_POOL,
1992                    "0x%08x: Free pSocket, %d bytes\r\n",
1993                    pSocket,
1994                    sizeof ( *pSocket )));
1995          errno = 0;
1996        }
1997        else {
1998          DEBUG (( DEBUG_ERROR | DEBUG_POOL,
1999                    "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2000                    pSocket,
2001                    Status ));
2002        }
2003      }
2004      else {
2005        DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
2006                    "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2007                    ChildHandle,
2008                    Status ));
2009      }
2010    }
2011    else {
2012      DEBUG (( DEBUG_ERROR | DEBUG_INFO,
2013                "ERROR - The socket was not in the socket list!\r\n" ));
2014      Status = EFI_NOT_FOUND;
2015    }
2016  }
2017  else {
2018    DEBUG (( DEBUG_ERROR,
2019              "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2020  }
2021
2022  //
2023  //  Return the errno value if possible
2024  //
2025  if ( NULL != pErrno ) {
2026    *pErrno = errno;
2027  }
2028
2029  //
2030  //  Return the operation status
2031  //
2032  DBG_EXIT_STATUS ( Status );
2033  return Status;
2034}
2035
2036
2037/** Get the local address.
2038
2039  This routine calls the network specific layer to get the network
2040  address of the local host connection point.
2041
2042  The ::getsockname routine calls this routine to obtain the network
2043  address associated with the local host connection point.
2044
2045  @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2046  @param[out]     pAddress        Network address to receive the local system address
2047  @param[in,out]  pAddressLength  Length of the local network address structure
2048  @param[out]     pErrno          Address to receive the errno value upon completion.
2049
2050  @retval EFI_SUCCESS - Local address successfully returned
2051 **/
2052EFI_STATUS
2053EslSocketGetLocalAddress (
2054  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2055  OUT struct sockaddr * pAddress,
2056  IN OUT socklen_t * pAddressLength,
2057  IN int * pErrno
2058  )
2059{
2060  socklen_t LengthInBytes;
2061  ESL_PORT * pPort;
2062  ESL_SOCKET * pSocket;
2063  EFI_STATUS Status;
2064  EFI_TPL TplPrevious;
2065
2066  DBG_ENTER ( );
2067
2068  //
2069  //  Assume success
2070  //
2071  Status = EFI_SUCCESS;
2072
2073  //
2074  //  Validate the socket
2075  //
2076  pSocket = NULL;
2077  if ( NULL != pSocketProtocol ) {
2078    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2079
2080    //
2081    //  Verify the socket state
2082    //
2083    EslSocketIsConfigured ( pSocket );
2084    if ( pSocket->bAddressSet ) {
2085      //
2086      //  Verify the address buffer and length address
2087      //
2088      if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
2089        //
2090        //  Verify the API
2091        //
2092        if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
2093          Status = EFI_UNSUPPORTED;
2094          pSocket->errno = ENOTSUP;
2095        }
2096        else {
2097          //
2098          //  Synchronize with the socket layer
2099          //
2100          RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2101
2102          //
2103          //  Verify that there is just a single connection
2104          //
2105          pPort = pSocket->pPortList;
2106          if ( NULL != pPort ) {
2107            //
2108            //  Verify the address length
2109            //
2110            LengthInBytes = pSocket->pApi->AddressLength;
2111            if (( LengthInBytes <= *pAddressLength )
2112              && ( 255 >= LengthInBytes )) {
2113              //
2114              //  Return the local address and address length
2115              //
2116              ZeroMem ( pAddress, LengthInBytes );
2117              pAddress->sa_len = (uint8_t)LengthInBytes;
2118              *pAddressLength = pAddress->sa_len;
2119              pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
2120              pSocket->errno = 0;
2121              Status = EFI_SUCCESS;
2122            }
2123            else {
2124              pSocket->errno = EINVAL;
2125              Status = EFI_INVALID_PARAMETER;
2126            }
2127          }
2128          else {
2129            pSocket->errno = ENOTCONN;
2130            Status = EFI_NOT_STARTED;
2131          }
2132
2133          //
2134          //  Release the socket layer synchronization
2135          //
2136          RESTORE_TPL ( TplPrevious );
2137        }
2138      }
2139      else {
2140        pSocket->errno = EINVAL;
2141        Status = EFI_INVALID_PARAMETER;
2142      }
2143    }
2144    else {
2145      //
2146      //  Address not set
2147      //
2148      Status = EFI_NOT_STARTED;
2149      pSocket->errno = EADDRNOTAVAIL;
2150    }
2151  }
2152
2153  //
2154  //  Return the operation status
2155  //
2156  if ( NULL != pErrno ) {
2157    if ( NULL != pSocket ) {
2158      *pErrno = pSocket->errno;
2159    }
2160    else {
2161      Status = EFI_INVALID_PARAMETER;
2162      *pErrno = ENOTSOCK;
2163    }
2164  }
2165  DBG_EXIT_STATUS ( Status );
2166  return Status;
2167}
2168
2169
2170/** Get the peer address.
2171
2172  This routine calls the network specific layer to get the remote
2173  system connection point.
2174
2175  The ::getpeername routine calls this routine to obtain the network
2176  address of the remote connection point.
2177
2178  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
2179  @param[out]     pAddress          Network address to receive the remote system address
2180  @param[in,out]  pAddressLength    Length of the remote network address structure
2181  @param[out]     pErrno            Address to receive the errno value upon completion.
2182
2183  @retval EFI_SUCCESS - Remote address successfully returned
2184 **/
2185EFI_STATUS
2186EslSocketGetPeerAddress (
2187  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2188  OUT struct sockaddr * pAddress,
2189  IN OUT socklen_t * pAddressLength,
2190  IN int * pErrno
2191  )
2192{
2193  socklen_t LengthInBytes;
2194  ESL_PORT * pPort;
2195  ESL_SOCKET * pSocket;
2196  EFI_STATUS Status;
2197  EFI_TPL TplPrevious;
2198
2199  DBG_ENTER ( );
2200
2201  //
2202  //  Assume success
2203  //
2204  Status = EFI_SUCCESS;
2205
2206  //
2207  //  Validate the socket
2208  //
2209  pSocket = NULL;
2210  if ( NULL != pSocketProtocol ) {
2211    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2212
2213    //
2214    //  Verify the socket state
2215    //
2216    Status = EslSocketIsConfigured ( pSocket );
2217    if ( !EFI_ERROR ( Status )) {
2218      //
2219      //  Verify the API
2220      //
2221      if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
2222        Status = EFI_UNSUPPORTED;
2223        pSocket->errno = ENOTSUP;
2224      }
2225      else {
2226        //
2227        //  Verify the address buffer and length address
2228        //
2229        if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
2230          //
2231          //  Verify the socket state
2232          //
2233          if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
2234            //
2235            //  Synchronize with the socket layer
2236            //
2237            RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2238
2239            //
2240            //  Verify that there is just a single connection
2241            //
2242            pPort = pSocket->pPortList;
2243            if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
2244              //
2245              //  Verify the address length
2246              //
2247              LengthInBytes = pSocket->pApi->AddressLength;
2248              if ( LengthInBytes <= *pAddressLength ) {
2249                //
2250                //  Return the local address
2251                //
2252                ZeroMem ( pAddress, LengthInBytes );
2253                pAddress->sa_len = (uint8_t)LengthInBytes;
2254                *pAddressLength = pAddress->sa_len;
2255                pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
2256                pSocket->errno = 0;
2257                Status = EFI_SUCCESS;
2258              }
2259              else {
2260                pSocket->errno = EINVAL;
2261                Status = EFI_INVALID_PARAMETER;
2262              }
2263            }
2264            else {
2265              pSocket->errno = ENOTCONN;
2266              Status = EFI_NOT_STARTED;
2267            }
2268
2269            //
2270            //  Release the socket layer synchronization
2271            //
2272            RESTORE_TPL ( TplPrevious );
2273          }
2274          else {
2275            pSocket->errno = ENOTCONN;
2276            Status = EFI_NOT_STARTED;
2277          }
2278        }
2279        else {
2280          pSocket->errno = EINVAL;
2281          Status = EFI_INVALID_PARAMETER;
2282        }
2283      }
2284    }
2285  }
2286
2287  //
2288  //  Return the operation status
2289  //
2290  if ( NULL != pErrno ) {
2291    if ( NULL != pSocket ) {
2292      *pErrno = pSocket->errno;
2293    }
2294    else {
2295      Status = EFI_INVALID_PARAMETER;
2296      *pErrno = ENOTSOCK;
2297    }
2298  }
2299  DBG_EXIT_STATUS ( Status );
2300  return Status;
2301}
2302
2303
2304/** Free the ESL_IO_MGMT event and structure.
2305
2306  This support routine walks the free list to close the event in
2307  the ESL_IO_MGMT structure and remove the structure from the free
2308  list.
2309
2310  See the \ref TransmitEngine section.
2311
2312  @param[in]  pPort         Address of an ::ESL_PORT structure
2313  @param[in]  ppFreeQueue   Address of the free queue head
2314  @param[in]  DebugFlags    Flags for debug messages
2315  @param[in]  pEventName    Zero terminated string containing the event name
2316
2317  @retval EFI_SUCCESS - The structures were properly initialized
2318**/
2319EFI_STATUS
2320EslSocketIoFree (
2321  IN ESL_PORT * pPort,
2322  IN ESL_IO_MGMT ** ppFreeQueue,
2323  IN UINTN DebugFlags,
2324  IN CHAR8 * pEventName
2325  )
2326{
2327  UINT8 * pBuffer;
2328  EFI_EVENT * pEvent;
2329  ESL_IO_MGMT * pIo;
2330  ESL_SOCKET * pSocket;
2331  EFI_STATUS Status;
2332
2333  DBG_ENTER ( );
2334
2335  //
2336  //  Assume success
2337  //
2338  Status = EFI_SUCCESS;
2339
2340  //
2341  //  Walk the list of IO structures
2342  //
2343  pSocket = pPort->pSocket;
2344  while ( *ppFreeQueue ) {
2345    //
2346    //  Free the event for this structure
2347    //
2348    pIo = *ppFreeQueue;
2349    pBuffer = (UINT8 *)pIo;
2350    pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
2351    pEvent = (EFI_EVENT *)pBuffer;
2352    Status = gBS->CloseEvent ( *pEvent );
2353    if ( EFI_ERROR ( Status )) {
2354      DEBUG (( DEBUG_ERROR | DebugFlags,
2355                "ERROR - Failed to close the %a event, Status: %r\r\n",
2356                pEventName,
2357                Status ));
2358      pSocket->errno = ENOMEM;
2359      break;
2360    }
2361    DEBUG (( DebugFlags,
2362              "0x%08x: Closed %a event 0x%08x\r\n",
2363              pIo,
2364              pEventName,
2365              *pEvent ));
2366
2367    //
2368    //  Remove this structure from the queue
2369    //
2370    *ppFreeQueue = pIo->pNext;
2371  }
2372
2373  //
2374  //  Return the operation status
2375  //
2376  DBG_EXIT_STATUS ( Status );
2377  return Status;
2378}
2379
2380
2381/** Initialize the ESL_IO_MGMT structures.
2382
2383  This support routine initializes the ESL_IO_MGMT structure and
2384  places them on to a free list.
2385
2386  This routine is called by ::EslSocketPortAllocate routines to prepare
2387  the transmit engines.  See the \ref TransmitEngine section.
2388
2389  @param[in]        pPort         Address of an ::ESL_PORT structure
2390  @param[in, out]   ppIo          Address containing the first structure address.  Upon
2391                                  return this buffer contains the next structure address.
2392  @param[in]        TokenCount    Number of structures to initialize
2393  @param[in]        ppFreeQueue   Address of the free queue head
2394  @param[in]        DebugFlags    Flags for debug messages
2395  @param[in]        pEventName    Zero terminated string containing the event name
2396  @param[in]        pfnCompletion Completion routine address
2397
2398  @retval EFI_SUCCESS - The structures were properly initialized
2399**/
2400EFI_STATUS
2401EslSocketIoInit (
2402  IN ESL_PORT * pPort,
2403  IN ESL_IO_MGMT ** ppIo,
2404  IN UINTN TokenCount,
2405  IN ESL_IO_MGMT ** ppFreeQueue,
2406  IN UINTN DebugFlags,
2407  IN CHAR8 * pEventName,
2408  IN PFN_API_IO_COMPLETE pfnCompletion
2409  )
2410{
2411  ESL_IO_MGMT * pEnd;
2412  EFI_EVENT * pEvent;
2413  ESL_IO_MGMT * pIo;
2414  ESL_SOCKET * pSocket;
2415  EFI_STATUS Status;
2416
2417  DBG_ENTER ( );
2418
2419  //
2420  //  Assume success
2421  //
2422  Status = EFI_SUCCESS;
2423
2424  //
2425  //  Walk the list of IO structures
2426  //
2427  pSocket = pPort->pSocket;
2428  pIo = *ppIo;
2429  pEnd = &pIo [ TokenCount ];
2430  while ( pEnd > pIo ) {
2431    //
2432    //  Initialize the IO structure
2433    //
2434    pIo->pPort = pPort;
2435    pIo->pPacket = NULL;
2436
2437    //
2438    //  Allocate the event for this structure
2439    //
2440    pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
2441    Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
2442                                TPL_SOCKETS,
2443                                (EFI_EVENT_NOTIFY)pfnCompletion,
2444                                pIo,
2445                                pEvent );
2446    if ( EFI_ERROR ( Status )) {
2447      DEBUG (( DEBUG_ERROR | DebugFlags,
2448                "ERROR - Failed to create the %a event, Status: %r\r\n",
2449                pEventName,
2450                Status ));
2451      pSocket->errno = ENOMEM;
2452      break;
2453    }
2454    DEBUG (( DebugFlags,
2455              "0x%08x: Created %a event 0x%08x\r\n",
2456              pIo,
2457              pEventName,
2458              *pEvent ));
2459
2460    //
2461    //  Add this structure to the queue
2462    //
2463    pIo->pNext = *ppFreeQueue;
2464    *ppFreeQueue = pIo;
2465
2466    //
2467    //  Set the next structure
2468    //
2469    pIo += 1;
2470  }
2471
2472  //
2473  //  Save the next structure
2474  //
2475  *ppIo = pIo;
2476
2477  //
2478  //  Return the operation status
2479  //
2480  DBG_EXIT_STATUS ( Status );
2481  return Status;
2482}
2483
2484
2485/** Determine if the socket is configured.
2486
2487  This support routine is called to determine if the socket if the
2488  configuration call was made to the network layer.  The following
2489  routines call this routine to verify that they may be successful
2490  in their operations:
2491  <ul>
2492    <li>::EslSocketGetLocalAddress</li>
2493    <li>::EslSocketGetPeerAddress</li>
2494    <li>::EslSocketPoll</li>
2495    <li>::EslSocketReceive</li>
2496    <li>::EslSocketTransmit</li>
2497  </ul>
2498
2499  @param[in]  pSocket       Address of an ::ESL_SOCKET structure
2500
2501  @retval EFI_SUCCESS - The socket is configured
2502**/
2503EFI_STATUS
2504EslSocketIsConfigured (
2505  IN ESL_SOCKET * pSocket
2506  )
2507{
2508  EFI_STATUS Status;
2509  EFI_TPL TplPrevious;
2510
2511  //
2512  //  Assume success
2513  //
2514  Status = EFI_SUCCESS;
2515
2516  //
2517  //  Verify the socket state
2518  //
2519  if ( !pSocket->bConfigured ) {
2520    DBG_ENTER ( );
2521
2522    //
2523    //  Verify the API
2524    //
2525    if ( NULL == pSocket->pApi->pfnIsConfigured ) {
2526      Status = EFI_UNSUPPORTED;
2527      pSocket->errno = ENOTSUP;
2528    }
2529    else {
2530      //
2531      //  Synchronize with the socket layer
2532      //
2533      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2534
2535      //
2536      //  Determine if the socket is configured
2537      //
2538      Status = pSocket->pApi->pfnIsConfigured ( pSocket );
2539
2540      //
2541      //  Release the socket layer synchronization
2542      //
2543      RESTORE_TPL ( TplPrevious );
2544
2545      //
2546      //  Set errno if a failure occurs
2547      //
2548      if ( EFI_ERROR ( Status )) {
2549        pSocket->errno = EADDRNOTAVAIL;
2550      }
2551    }
2552
2553    DBG_EXIT_STATUS ( Status );
2554  }
2555
2556  //
2557  //  Return the configuration status
2558  //
2559  return Status;
2560}
2561
2562
2563/** Establish the known port to listen for network connections.
2564
2565  This routine calls into the network protocol layer to establish
2566  a handler that is called upon connection completion.  The handler
2567  is responsible for inserting the connection into the FIFO.
2568
2569  The ::listen routine indirectly calls this routine to place the
2570  socket into a state that enables connection attempts.  Connections
2571  are placed in a FIFO that is serviced by the application.  The
2572  application calls the ::accept (::EslSocketAccept) routine to
2573  remove the next connection from the FIFO and get the associated
2574  socket and address.
2575
2576  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2577  @param[in]  Backlog         Backlog specifies the maximum FIFO depth for
2578                              the connections waiting for the application
2579                              to call accept.  Connection attempts received
2580                              while the queue is full are refused.
2581  @param[out] pErrno          Address to receive the errno value upon completion.
2582
2583  @retval EFI_SUCCESS - Socket successfully created
2584  @retval Other - Failed to enable the socket for listen
2585**/
2586EFI_STATUS
2587EslSocketListen (
2588  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2589  IN INT32 Backlog,
2590  OUT int * pErrno
2591  )
2592{
2593  ESL_SOCKET * pSocket;
2594  EFI_STATUS Status;
2595  EFI_STATUS TempStatus;
2596  EFI_TPL TplPrevious;
2597
2598  DBG_ENTER ( );
2599
2600  //
2601  //  Assume success
2602  //
2603  Status = EFI_SUCCESS;
2604
2605  //
2606  //  Validate the socket
2607  //
2608  pSocket = NULL;
2609  if ( NULL != pSocketProtocol ) {
2610    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2611
2612    //
2613    //  Verify the API
2614    //
2615    if ( NULL == pSocket->pApi->pfnListen ) {
2616      Status = EFI_UNSUPPORTED;
2617      pSocket->errno = ENOTSUP;
2618    }
2619    else {
2620      //
2621      //  Assume success
2622      //
2623      pSocket->Status = EFI_SUCCESS;
2624      pSocket->errno = 0;
2625
2626      //
2627      //  Verify that the bind operation was successful
2628      //
2629      if ( SOCKET_STATE_BOUND == pSocket->State ) {
2630        //
2631        //  Synchronize with the socket layer
2632        //
2633        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2634
2635        //
2636        //  Create the event for SocketAccept completion
2637        //
2638        Status = gBS->CreateEvent ( 0,
2639                                    TPL_SOCKETS,
2640                                    NULL,
2641                                    NULL,
2642                                    &pSocket->WaitAccept );
2643        if ( !EFI_ERROR ( Status )) {
2644          DEBUG (( DEBUG_POOL,
2645                    "0x%08x: Created WaitAccept event\r\n",
2646                    pSocket->WaitAccept ));
2647          //
2648          //  Set the maximum FIFO depth
2649          //
2650          if ( 0 >= Backlog ) {
2651            Backlog = MAX_PENDING_CONNECTIONS;
2652          }
2653          else {
2654            if ( SOMAXCONN < Backlog ) {
2655              Backlog = SOMAXCONN;
2656            }
2657            else {
2658              pSocket->MaxFifoDepth = Backlog;
2659            }
2660          }
2661
2662          //
2663          //  Initiate the connection attempt listen
2664          //
2665          Status = pSocket->pApi->pfnListen ( pSocket );
2666
2667          //
2668          //  Place the socket in the listen state if successful
2669          //
2670          if ( !EFI_ERROR ( Status )) {
2671            pSocket->State = SOCKET_STATE_LISTENING;
2672            pSocket->bListenCalled = TRUE;
2673          }
2674          else {
2675            //
2676            //  Not waiting for SocketAccept to complete
2677            //
2678            TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
2679            if ( !EFI_ERROR ( TempStatus )) {
2680              DEBUG (( DEBUG_POOL,
2681                        "0x%08x: Closed WaitAccept event\r\n",
2682                        pSocket->WaitAccept ));
2683              pSocket->WaitAccept = NULL;
2684            }
2685            else {
2686              DEBUG (( DEBUG_ERROR | DEBUG_POOL,
2687                        "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2688                        TempStatus ));
2689              ASSERT ( EFI_SUCCESS == TempStatus );
2690            }
2691          }
2692        }
2693        else {
2694          DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
2695                    "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2696                    Status ));
2697          pSocket->errno = ENOMEM;
2698        }
2699
2700        //
2701        //  Release the socket layer synchronization
2702        //
2703        RESTORE_TPL ( TplPrevious );
2704      }
2705      else {
2706        DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
2707                  "ERROR - Bind operation must be performed first!\r\n" ));
2708        pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
2709                                                                           : EINVAL;
2710        Status = EFI_NO_MAPPING;
2711      }
2712    }
2713  }
2714
2715  //
2716  //  Return the operation status
2717  //
2718  if ( NULL != pErrno ) {
2719    if ( NULL != pSocket ) {
2720      *pErrno = pSocket->errno;
2721    }
2722    else {
2723      Status = EFI_INVALID_PARAMETER;
2724      *pErrno = ENOTSOCK;
2725    }
2726  }
2727  DBG_EXIT_STATUS ( Status );
2728  return Status;
2729}
2730
2731
2732/** Get the socket options.
2733
2734  This routine handles the socket level options and passes the
2735  others to the network specific layer.
2736
2737  The ::getsockopt routine calls this routine to retrieve the
2738  socket options one at a time by name.
2739
2740  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
2741  @param[in]      level             Option protocol level
2742  @param[in]      OptionName        Name of the option
2743  @param[out]     pOptionValue      Buffer to receive the option value
2744  @param[in,out]  pOptionLength     Length of the buffer in bytes,
2745                                    upon return length of the option value in bytes
2746  @param[out]     pErrno            Address to receive the errno value upon completion.
2747
2748  @retval EFI_SUCCESS - Socket data successfully received
2749 **/
2750EFI_STATUS
2751EslSocketOptionGet (
2752  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2753  IN int level,
2754  IN int OptionName,
2755  OUT void * __restrict pOptionValue,
2756  IN OUT socklen_t * __restrict pOptionLength,
2757  IN int * pErrno
2758  )
2759{
2760  int errno;
2761  socklen_t LengthInBytes;
2762  socklen_t MaxBytes;
2763  CONST UINT8 * pOptionData;
2764  ESL_SOCKET * pSocket;
2765  EFI_STATUS Status;
2766
2767  DBG_ENTER ( );
2768
2769  //
2770  //  Assume failure
2771  //
2772  errno = EINVAL;
2773  Status = EFI_INVALID_PARAMETER;
2774
2775  //
2776  //  Validate the socket
2777  //
2778  pSocket = NULL;
2779  if ( NULL == pSocketProtocol ) {
2780    DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
2781  }
2782  else if ( NULL == pOptionValue ) {
2783    DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
2784  }
2785  else if ( NULL == pOptionLength ) {
2786    DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
2787  }
2788  else {
2789    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2790    LengthInBytes = 0;
2791    MaxBytes = *pOptionLength;
2792    pOptionData = NULL;
2793    switch ( level ) {
2794    default:
2795      //
2796      //  See if the protocol will handle the option
2797      //
2798      if ( NULL != pSocket->pApi->pfnOptionGet ) {
2799        if ( pSocket->pApi->DefaultProtocol == level ) {
2800          Status = pSocket->pApi->pfnOptionGet ( pSocket,
2801                                                 OptionName,
2802                                                 (CONST void ** __restrict)&pOptionData,
2803                                                 &LengthInBytes );
2804          errno = pSocket->errno;
2805          break;
2806        }
2807        else {
2808          //
2809          //  Protocol not supported
2810          //
2811          DEBUG (( DEBUG_OPTION,
2812                    "ERROR - The socket does not support this protocol!\r\n" ));
2813        }
2814      }
2815      else {
2816        //
2817        //  Protocol level not supported
2818        //
2819        DEBUG (( DEBUG_OPTION,
2820                  "ERROR - %a does not support any options!\r\n",
2821                  pSocket->pApi->pName ));
2822      }
2823      errno = ENOPROTOOPT;
2824      Status = EFI_INVALID_PARAMETER;
2825      break;
2826
2827    case SOL_SOCKET:
2828      switch ( OptionName ) {
2829      default:
2830        //
2831        //  Socket option not supported
2832        //
2833        DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
2834        errno = EINVAL;
2835        Status = EFI_INVALID_PARAMETER;
2836        break;
2837
2838      case SO_ACCEPTCONN:
2839        //
2840        //  Return the listen flag
2841        //
2842        pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;
2843        LengthInBytes = sizeof ( pSocket->bListenCalled );
2844        break;
2845
2846      case SO_DEBUG:
2847        //
2848        //  Return the debug flags
2849        //
2850        pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
2851        LengthInBytes = sizeof ( pSocket->bOobInLine );
2852        break;
2853
2854      case SO_OOBINLINE:
2855        //
2856        //  Return the out-of-band inline flag
2857        //
2858        pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
2859        LengthInBytes = sizeof ( pSocket->bOobInLine );
2860        break;
2861
2862      case SO_RCVTIMEO:
2863        //
2864        //  Return the receive timeout
2865        //
2866        pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;
2867        LengthInBytes = sizeof ( pSocket->RxTimeout );
2868        break;
2869
2870      case SO_RCVBUF:
2871        //
2872        //  Return the maximum receive buffer size
2873        //
2874        pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;
2875        LengthInBytes = sizeof ( pSocket->MaxRxBuf );
2876        break;
2877
2878      case SO_REUSEADDR:
2879        //
2880        //  Return the address reuse flag
2881        //
2882        pOptionData = (UINT8 *)&pSocket->bReUseAddr;
2883        LengthInBytes = sizeof ( pSocket->bReUseAddr );
2884        break;
2885
2886      case SO_SNDBUF:
2887        //
2888        //  Return the maximum transmit buffer size
2889        //
2890        pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;
2891        LengthInBytes = sizeof ( pSocket->MaxTxBuf );
2892        break;
2893
2894      case SO_TYPE:
2895        //
2896        //  Return the socket type
2897        //
2898        pOptionData = (CONST UINT8 *)&pSocket->Type;
2899        LengthInBytes = sizeof ( pSocket->Type );
2900        break;
2901      }
2902      break;
2903    }
2904
2905    //
2906    //  Return the option length
2907    //
2908    *pOptionLength = LengthInBytes;
2909
2910    //
2911    //  Determine if the option is present
2912    //
2913    if ( 0 != LengthInBytes ) {
2914      //
2915      //  Silently truncate the value length
2916      //
2917      if ( LengthInBytes > MaxBytes ) {
2918        DEBUG (( DEBUG_OPTION,
2919                  "INFO - Truncating option from %d to %d bytes\r\n",
2920                  LengthInBytes,
2921                  MaxBytes ));
2922        LengthInBytes = MaxBytes;
2923      }
2924
2925      //
2926      //  Return the value
2927      //
2928      CopyMem ( pOptionValue, pOptionData, LengthInBytes );
2929
2930      //
2931      //  Zero fill any remaining space
2932      //
2933      if ( LengthInBytes < MaxBytes ) {
2934        ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
2935      }
2936      errno = 0;
2937      Status = EFI_SUCCESS;
2938    }
2939  }
2940
2941  //
2942  //  Return the operation status
2943  //
2944  if ( NULL != pErrno ) {
2945    *pErrno = errno;
2946  }
2947  DBG_EXIT_STATUS ( Status );
2948  return Status;
2949}
2950
2951
2952/** Set the socket options.
2953
2954  This routine handles the socket level options and passes the
2955  others to the network specific layer.
2956
2957  The ::setsockopt routine calls this routine to adjust the socket
2958  options one at a time by name.
2959
2960  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2961  @param[in]  level           Option protocol level
2962  @param[in]  OptionName      Name of the option
2963  @param[in]  pOptionValue    Buffer containing the option value
2964  @param[in]  OptionLength    Length of the buffer in bytes
2965  @param[out] pErrno          Address to receive the errno value upon completion.
2966
2967  @retval EFI_SUCCESS - Option successfully set
2968**/
2969EFI_STATUS
2970EslSocketOptionSet (
2971  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2972  IN int level,
2973  IN int OptionName,
2974  IN CONST void * pOptionValue,
2975  IN socklen_t OptionLength,
2976  IN int * pErrno
2977  )
2978{
2979  BOOLEAN bTrueFalse;
2980  int errno;
2981  socklen_t LengthInBytes;
2982  UINT8 * pOptionData;
2983  ESL_SOCKET * pSocket;
2984  EFI_STATUS Status;
2985
2986  DBG_ENTER ( );
2987
2988  //
2989  //  Assume failure
2990  //
2991  errno = EINVAL;
2992  Status = EFI_INVALID_PARAMETER;
2993
2994  //
2995  //  Validate the socket
2996  //
2997  pSocket = NULL;
2998  if ( NULL == pSocketProtocol ) {
2999    DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
3000  }
3001  else if ( NULL == pOptionValue ) {
3002    DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
3003  }
3004  else
3005  {
3006    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
3007    if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
3008      DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
3009    }
3010    else {
3011      LengthInBytes = 0;
3012      pOptionData = NULL;
3013      switch ( level ) {
3014      default:
3015        //
3016        //  See if the protocol will handle the option
3017        //
3018        if ( NULL != pSocket->pApi->pfnOptionSet ) {
3019          if ( pSocket->pApi->DefaultProtocol == level ) {
3020            Status = pSocket->pApi->pfnOptionSet ( pSocket,
3021                                                   OptionName,
3022                                                   pOptionValue,
3023                                                   OptionLength );
3024            errno = pSocket->errno;
3025            break;
3026          }
3027          else {
3028            //
3029            //  Protocol not supported
3030            //
3031            DEBUG (( DEBUG_OPTION,
3032                      "ERROR - The socket does not support this protocol!\r\n" ));
3033          }
3034        }
3035        else {
3036          //
3037          //  Protocol level not supported
3038          //
3039          DEBUG (( DEBUG_OPTION,
3040                    "ERROR - %a does not support any options!\r\n",
3041                    pSocket->pApi->pName ));
3042        }
3043        errno = ENOPROTOOPT;
3044        Status = EFI_INVALID_PARAMETER;
3045        break;
3046
3047      case SOL_SOCKET:
3048        switch ( OptionName ) {
3049        default:
3050          //
3051          //  Option not supported
3052          //
3053          DEBUG (( DEBUG_OPTION,
3054                    "ERROR - Sockets does not support this option!\r\n" ));
3055          errno = EINVAL;
3056          Status = EFI_INVALID_PARAMETER;
3057          break;
3058
3059        case SO_DEBUG:
3060          //
3061          //  Set the debug flags
3062          //
3063          pOptionData = (UINT8 *)&pSocket->bOobInLine;
3064          LengthInBytes = sizeof ( pSocket->bOobInLine );
3065          break;
3066
3067        case SO_OOBINLINE:
3068          pOptionData = (UINT8 *)&pSocket->bOobInLine;
3069          LengthInBytes = sizeof ( pSocket->bOobInLine );
3070
3071          //
3072          //  Validate the option length
3073          //
3074          if ( sizeof ( UINT32 ) == OptionLength ) {
3075            //
3076            //  Restrict the input to TRUE or FALSE
3077            //
3078            bTrueFalse = TRUE;
3079            if ( 0 == *(UINT32 *)pOptionValue ) {
3080              bTrueFalse = FALSE;
3081            }
3082            pOptionValue = &bTrueFalse;
3083          }
3084          else {
3085            //
3086            //  Force an invalid option length error
3087            //
3088            OptionLength = LengthInBytes - 1;
3089          }
3090          break;
3091
3092        case SO_RCVTIMEO:
3093          //
3094          //  Return the receive timeout
3095          //
3096          pOptionData = (UINT8 *)&pSocket->RxTimeout;
3097          LengthInBytes = sizeof ( pSocket->RxTimeout );
3098          break;
3099
3100        case SO_RCVBUF:
3101          //
3102          //  Return the maximum receive buffer size
3103          //
3104          pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
3105          LengthInBytes = sizeof ( pSocket->MaxRxBuf );
3106          break;
3107
3108        case SO_REUSEADDR:
3109          //
3110          //  Return the address reuse flag
3111          //
3112          pOptionData = (UINT8 *)&pSocket->bReUseAddr;
3113          LengthInBytes = sizeof ( pSocket->bReUseAddr );
3114          break;
3115
3116        case SO_SNDBUF:
3117          //
3118          //  Send buffer size
3119          //
3120          //
3121          //  Return the maximum transmit buffer size
3122          //
3123          pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
3124          LengthInBytes = sizeof ( pSocket->MaxTxBuf );
3125          break;
3126        }
3127        break;
3128      }
3129
3130      //
3131      //  Determine if an option was found
3132      //
3133      if ( 0 != LengthInBytes ) {
3134        //
3135        //  Validate the option length
3136        //
3137        if ( LengthInBytes <= OptionLength ) {
3138          //
3139          //  Set the option value
3140          //
3141          CopyMem ( pOptionData, pOptionValue, LengthInBytes );
3142          errno = 0;
3143          Status = EFI_SUCCESS;
3144        }
3145        else {
3146          DEBUG (( DEBUG_OPTION,
3147                    "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3148                    OptionLength,
3149                    LengthInBytes ));
3150        }
3151      }
3152    }
3153  }
3154
3155  //
3156  //  Return the operation status
3157  //
3158  if ( NULL != pErrno ) {
3159    *pErrno = errno;
3160  }
3161  DBG_EXIT_STATUS ( Status );
3162  return Status;
3163}
3164
3165
3166/**  Allocate a packet for a receive or transmit operation.
3167
3168  This support routine is called by ::EslSocketRxStart and the
3169  network specific TxBuffer routines to get buffer space for the
3170  next operation.
3171
3172  @param[in]  ppPacket      Address to receive the ::ESL_PACKET structure
3173  @param[in]  LengthInBytes Length of the packet structure
3174  @param[in]  ZeroBytes     Length of packet to zero
3175  @param[in]  DebugFlags    Flags for debug messages
3176
3177  @retval EFI_SUCCESS - The packet was allocated successfully
3178**/
3179EFI_STATUS
3180EslSocketPacketAllocate (
3181  IN ESL_PACKET ** ppPacket,
3182  IN size_t LengthInBytes,
3183  IN size_t ZeroBytes,
3184  IN UINTN DebugFlags
3185  )
3186{
3187  ESL_PACKET * pPacket;
3188  EFI_STATUS Status;
3189
3190  DBG_ENTER ( );
3191
3192  //
3193  //  Allocate a packet structure
3194  //
3195  LengthInBytes += sizeof ( *pPacket )
3196                - sizeof ( pPacket->Op );
3197  Status = gBS->AllocatePool ( EfiRuntimeServicesData,
3198                               LengthInBytes,
3199                               (VOID **)&pPacket );
3200  if ( !EFI_ERROR ( Status )) {
3201    DEBUG (( DebugFlags | DEBUG_POOL,
3202              "0x%08x: Allocate pPacket, %d bytes\r\n",
3203              pPacket,
3204              LengthInBytes ));
3205    if ( 0 != ZeroBytes ) {
3206      ZeroMem ( &pPacket->Op, ZeroBytes );
3207    }
3208    pPacket->PacketSize = LengthInBytes;
3209  }
3210  else {
3211    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
3212              "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3213              LengthInBytes,
3214              Status ));
3215    pPacket = NULL;
3216  }
3217
3218  //
3219  //  Return the packet
3220  //
3221  *ppPacket = pPacket;
3222
3223  //
3224  //  Return the operation status
3225  //
3226  DBG_EXIT_STATUS ( Status );
3227  return Status;
3228}
3229
3230
3231/** Free a packet used for receive or transmit operation.
3232
3233  This support routine is called by the network specific Close
3234  and TxComplete routines and during error cases in RxComplete
3235  and TxBuffer.  Note that the network layers typically place
3236  receive packets on the ESL_SOCKET::pRxFree list for reuse.
3237
3238  @param[in]  pPacket     Address of an ::ESL_PACKET structure
3239  @param[in]  DebugFlags  Flags for debug messages
3240
3241  @retval EFI_SUCCESS - The packet was allocated successfully
3242**/
3243EFI_STATUS
3244EslSocketPacketFree (
3245  IN ESL_PACKET * pPacket,
3246  IN UINTN DebugFlags
3247  )
3248{
3249  UINTN LengthInBytes;
3250  EFI_STATUS Status;
3251
3252  DBG_ENTER ( );
3253
3254  //
3255  //  Free a packet structure
3256  //
3257  LengthInBytes = pPacket->PacketSize;
3258  Status = gBS->FreePool ( pPacket );
3259  if ( !EFI_ERROR ( Status )) {
3260    DEBUG (( DebugFlags | DEBUG_POOL,
3261              "0x%08x: Free pPacket, %d bytes\r\n",
3262              pPacket,
3263              LengthInBytes ));
3264  }
3265  else {
3266    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
3267              "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3268              pPacket,
3269              Status ));
3270  }
3271
3272  //
3273  //  Return the operation status
3274  //
3275  DBG_EXIT_STATUS ( Status );
3276  return Status;
3277}
3278
3279
3280/** Poll a socket for pending activity.
3281
3282  This routine builds a detected event mask which is returned to
3283  the caller in the buffer provided.
3284
3285  The ::poll routine calls this routine to determine if the socket
3286  needs to be serviced as a result of connection, error, receive or
3287  transmit activity.
3288
3289  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3290  @param[in]  Events          Events of interest for this socket
3291  @param[in]  pEvents         Address to receive the detected events
3292  @param[out] pErrno          Address to receive the errno value upon completion.
3293
3294  @retval EFI_SUCCESS - Socket successfully polled
3295  @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3296**/
3297EFI_STATUS
3298EslSocketPoll (
3299  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
3300  IN short Events,
3301  IN short * pEvents,
3302  IN int * pErrno
3303  )
3304{
3305  short DetectedEvents;
3306  ESL_SOCKET * pSocket;
3307  EFI_STATUS Status;
3308  EFI_TPL TplPrevious;
3309  short ValidEvents;
3310  int   _errno = EINVAL;
3311
3312  DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
3313
3314  //
3315  //  Assume success
3316  //
3317  Status = EFI_SUCCESS;
3318  DetectedEvents = 0;
3319  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
3320  pSocket->errno = 0;
3321
3322  //
3323  //  Verify the socket state
3324  //
3325  Status = EslSocketIsConfigured ( pSocket );
3326  if ( !EFI_ERROR ( Status )) {
3327    //
3328    //  Check for invalid events
3329    //
3330    ValidEvents = POLLIN
3331                | POLLPRI
3332                | POLLOUT | POLLWRNORM
3333                | POLLERR
3334                | POLLHUP
3335                | POLLNVAL
3336                | POLLRDNORM
3337                | POLLRDBAND
3338                | POLLWRBAND ;
3339    if ( 0 != ( Events & ( ~ValidEvents ))) {
3340      DetectedEvents |= POLLNVAL;
3341      DEBUG (( DEBUG_INFO | DEBUG_POLL,
3342                "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3343                Events & ValidEvents,
3344                Events & ( ~ValidEvents )));
3345    }
3346    else {
3347      //
3348      //  Synchronize with the socket layer
3349      //
3350      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
3351
3352      //
3353      //  Increase the network performance by extending the
3354      //  polling (idle) loop down into the LAN driver
3355      //
3356      EslSocketRxPoll ( pSocket );
3357
3358      //
3359      //  Release the socket layer synchronization
3360      //
3361      RESTORE_TPL ( TplPrevious );
3362
3363      //
3364      //  Check for pending connections
3365      //
3366      if ( 0 != pSocket->FifoDepth ) {
3367        //
3368        //  A connection is waiting for an accept call
3369        //  See posix connect documentation at
3370        //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3371        //
3372        DetectedEvents |= POLLIN | POLLRDNORM;
3373      }
3374      if ( pSocket->bConnected ) {
3375        //
3376        //  A connection is present
3377        //  See posix connect documentation at
3378        //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3379        //
3380        DetectedEvents |= POLLOUT | POLLWRNORM;
3381      }
3382
3383      //
3384      //  The following bits are set based upon the POSIX poll documentation at
3385      //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3386      //
3387
3388      //
3389      //  Check for urgent receive data
3390      //
3391      if ( 0 < pSocket->RxOobBytes ) {
3392        DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;
3393      }
3394
3395      //
3396      //  Check for normal receive data
3397      //
3398      if (( 0 < pSocket->RxBytes )
3399        || ( EFI_SUCCESS != pSocket->RxError )) {
3400        DetectedEvents |= POLLRDNORM | POLLIN;
3401      }
3402
3403      //
3404      //  Handle the receive errors
3405      //
3406      if (( EFI_SUCCESS != pSocket->RxError )
3407        && ( 0 == ( DetectedEvents & POLLIN ))) {
3408        DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;
3409      }
3410
3411      //
3412      //  Check for urgent transmit data buffer space
3413      //
3414      if (( MAX_TX_DATA > pSocket->TxOobBytes )
3415        || ( EFI_SUCCESS != pSocket->TxError )) {
3416        DetectedEvents |= POLLWRBAND;
3417      }
3418
3419      //
3420      //  Check for normal transmit data buffer space
3421      //
3422      if (( MAX_TX_DATA > pSocket->TxBytes )
3423        || ( EFI_SUCCESS != pSocket->TxError )) {
3424        DetectedEvents |= POLLWRNORM;
3425      }
3426
3427      //
3428      //  Handle the transmit error
3429      //
3430      if ( EFI_ERROR ( pSocket->TxError )) {
3431        DetectedEvents |= POLLERR;
3432      }
3433      _errno = pSocket->errno;
3434    }
3435  }
3436
3437  //
3438  //  Return the detected events
3439  //
3440  *pEvents = DetectedEvents & ( Events
3441                              | POLLERR
3442                              | POLLHUP
3443                              | POLLNVAL );
3444  if ( NULL != pErrno ) {
3445    *pErrno = _errno;
3446  }
3447  //
3448  //  Return the operation status
3449  //
3450  DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));
3451  return Status;
3452}
3453
3454
3455/** Allocate and initialize a ESL_PORT structure.
3456
3457  This routine initializes an ::ESL_PORT structure for use by
3458  the socket.  This routine calls a routine via
3459  ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3460  specific resources.  The resources are released later by the
3461  \ref PortCloseStateMachine.
3462
3463  This support routine is called by:
3464  <ul>
3465    <li>::EslSocketBind</li>
3466    <li>::EslTcp4ListenComplete</li>
3467  </ul>
3468  to connect the socket with the underlying network adapter
3469  to the socket.
3470
3471  @param[in]  pSocket     Address of an ::ESL_SOCKET structure.
3472  @param[in]  pService    Address of an ::ESL_SERVICE structure.
3473  @param[in]  ChildHandle Network protocol child handle
3474  @param[in]  pSockAddr   Address of a sockaddr structure that contains the
3475                          connection point on the local machine.  An IPv4 address
3476                          of INADDR_ANY specifies that the connection is made to
3477                          all of the network stacks on the platform.  Specifying a
3478                          specific IPv4 address restricts the connection to the
3479                          network stack supporting that address.  Specifying zero
3480                          for the port causes the network layer to assign a port
3481                          number from the dynamic range.  Specifying a specific
3482                          port number causes the network layer to use that port.
3483  @param[in]  bBindTest   TRUE if EslSocketBindTest should be called
3484  @param[in]  DebugFlags  Flags for debug messages
3485  @param[out] ppPort      Buffer to receive new ::ESL_PORT structure address
3486
3487  @retval EFI_SUCCESS - Socket successfully created
3488**/
3489EFI_STATUS
3490EslSocketPortAllocate (
3491  IN ESL_SOCKET * pSocket,
3492  IN ESL_SERVICE * pService,
3493  IN EFI_HANDLE ChildHandle,
3494  IN CONST struct sockaddr * pSockAddr,
3495  IN BOOLEAN bBindTest,
3496  IN UINTN DebugFlags,
3497  OUT ESL_PORT ** ppPort
3498  )
3499{
3500  UINTN LengthInBytes;
3501  UINT8 * pBuffer;
3502  ESL_IO_MGMT * pIo;
3503  ESL_LAYER * pLayer;
3504  ESL_PORT * pPort;
3505  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
3506  CONST ESL_SOCKET_BINDING * pSocketBinding;
3507  EFI_STATUS Status;
3508  EFI_STATUS TempStatus;
3509
3510  DBG_ENTER ( );
3511
3512  //
3513  //  Verify the socket layer synchronization
3514  //
3515  VERIFY_TPL ( TPL_SOCKETS );
3516
3517  //
3518  //  Use for/break instead of goto
3519  pSocketBinding = pService->pSocketBinding;
3520  for ( ; ; ) {
3521    //
3522    //  Allocate a port structure
3523    //
3524    pLayer = &mEslLayer;
3525    LengthInBytes = sizeof ( *pPort )
3526                  + ESL_STRUCTURE_ALIGNMENT_BYTES
3527                  + (( pSocketBinding->RxIo
3528                       + pSocketBinding->TxIoNormal
3529                       + pSocketBinding->TxIoUrgent )
3530                     * sizeof ( ESL_IO_MGMT ));
3531    pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
3532    if ( NULL == pPort ) {
3533      Status = EFI_OUT_OF_RESOURCES;
3534      pSocket->errno = ENOMEM;
3535      break;
3536    }
3537    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
3538              "0x%08x: Allocate pPort, %d bytes\r\n",
3539              pPort,
3540              LengthInBytes ));
3541
3542    //
3543    //  Initialize the port
3544    //
3545    pPort->DebugFlags = DebugFlags;
3546    pPort->Handle = ChildHandle;
3547    pPort->pService = pService;
3548    pPort->pServiceBinding = pService->pServiceBinding;
3549    pPort->pSocket = pSocket;
3550    pPort->pSocketBinding = pService->pSocketBinding;
3551    pPort->Signature = PORT_SIGNATURE;
3552
3553    //
3554    //  Open the port protocol
3555    //
3556    Status = gBS->OpenProtocol ( pPort->Handle,
3557                                 pSocketBinding->pNetworkProtocolGuid,
3558                                 &pPort->pProtocol.v,
3559                                 pLayer->ImageHandle,
3560                                 NULL,
3561                                 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
3562    if ( EFI_ERROR ( Status )) {
3563      DEBUG (( DEBUG_ERROR | DebugFlags,
3564                "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3565                pPort->Handle ));
3566      pSocket->errno = EEXIST;
3567      break;
3568    }
3569    DEBUG (( DebugFlags,
3570              "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3571              pPort->pProtocol.v,
3572              pPort->Handle ));
3573
3574    //
3575    //  Initialize the port specific resources
3576    //
3577    Status = pSocket->pApi->pfnPortAllocate ( pPort,
3578                                              DebugFlags );
3579    if ( EFI_ERROR ( Status )) {
3580      break;
3581    }
3582
3583    //
3584    //  Set the local address
3585    //
3586    Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
3587    if ( EFI_ERROR ( Status )) {
3588      break;
3589    }
3590
3591    //
3592    //  Test the address/port configuration
3593    //
3594    if ( bBindTest ) {
3595      Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
3596      if ( EFI_ERROR ( Status )) {
3597        break;
3598      }
3599    }
3600
3601    //
3602    //  Initialize the receive structures
3603    //
3604    pBuffer = (UINT8 *)&pPort[ 1 ];
3605    pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
3606    pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
3607    pIo = (ESL_IO_MGMT *)pBuffer;
3608    if (( 0 != pSocketBinding->RxIo )
3609      && ( NULL != pSocket->pApi->pfnRxComplete )) {
3610      Status = EslSocketIoInit ( pPort,
3611                                 &pIo,
3612                                 pSocketBinding->RxIo,
3613                                 &pPort->pRxFree,
3614                                 DebugFlags | DEBUG_POOL,
3615                                 "receive",
3616                                 pSocket->pApi->pfnRxComplete );
3617      if ( EFI_ERROR ( Status )) {
3618        break;
3619      }
3620    }
3621
3622    //
3623    //  Initialize the urgent transmit structures
3624    //
3625    if (( 0 != pSocketBinding->TxIoUrgent )
3626      && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
3627      Status = EslSocketIoInit ( pPort,
3628                                 &pIo,
3629                                 pSocketBinding->TxIoUrgent,
3630                                 &pPort->pTxOobFree,
3631                                 DebugFlags | DEBUG_POOL,
3632                                 "urgent transmit",
3633                                 pSocket->pApi->pfnTxOobComplete );
3634      if ( EFI_ERROR ( Status )) {
3635        break;
3636      }
3637    }
3638
3639    //
3640    //  Initialize the normal transmit structures
3641    //
3642    if (( 0 != pSocketBinding->TxIoNormal )
3643      && ( NULL != pSocket->pApi->pfnTxComplete )) {
3644      Status = EslSocketIoInit ( pPort,
3645                                 &pIo,
3646                                 pSocketBinding->TxIoNormal,
3647                                 &pPort->pTxFree,
3648                                 DebugFlags | DEBUG_POOL,
3649                                 "normal transmit",
3650                                 pSocket->pApi->pfnTxComplete );
3651      if ( EFI_ERROR ( Status )) {
3652        break;
3653      }
3654    }
3655
3656    //
3657    //  Add this port to the socket
3658    //
3659    pPort->pLinkSocket = pSocket->pPortList;
3660    pSocket->pPortList = pPort;
3661    DEBUG (( DebugFlags,
3662              "0x%08x: Socket adding port: 0x%08x\r\n",
3663              pSocket,
3664              pPort ));
3665
3666    //
3667    //  Add this port to the service
3668    //
3669    pPort->pLinkService = pService->pPortList;
3670    pService->pPortList = pPort;
3671
3672    //
3673    //  Return the port
3674    //
3675    *ppPort = pPort;
3676    break;
3677  }
3678
3679  //
3680  //  Clean up after the error if necessary
3681  //
3682  if ( EFI_ERROR ( Status )) {
3683    if ( NULL != pPort ) {
3684      //
3685      //  Close the port
3686      //
3687      EslSocketPortClose ( pPort );
3688    }
3689    else {
3690      //
3691      //  Close the port if necessary
3692      //
3693      pServiceBinding = pService->pServiceBinding;
3694      TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
3695                                                   ChildHandle );
3696      if ( !EFI_ERROR ( TempStatus )) {
3697        DEBUG (( DEBUG_BIND | DEBUG_POOL,
3698                  "0x%08x: %s port handle destroyed\r\n",
3699                  ChildHandle,
3700                  pSocketBinding->pName ));
3701      }
3702      else {
3703        DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
3704                  "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3705                  pSocketBinding->pName,
3706                  ChildHandle,
3707                  TempStatus ));
3708        ASSERT ( EFI_SUCCESS == TempStatus );
3709      }
3710    }
3711  }
3712  //
3713  //  Return the operation status
3714  //
3715  DBG_EXIT_STATUS ( Status );
3716  return Status;
3717}
3718
3719
3720/** Close a port.
3721
3722  This routine releases the resources allocated by ::EslSocketPortAllocate.
3723  This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3724  specific resources.
3725
3726  This routine is called by:
3727  <ul>
3728    <li>::EslSocketPortAllocate - Port initialization failure</li>
3729    <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3730    <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3731  </ul>
3732  See the \ref PortCloseStateMachine section.
3733
3734  @param[in]  pPort       Address of an ::ESL_PORT structure.
3735
3736  @retval EFI_SUCCESS     The port is closed
3737  @retval other           Port close error
3738**/
3739EFI_STATUS
3740EslSocketPortClose (
3741  IN ESL_PORT * pPort
3742  )
3743{
3744  UINTN DebugFlags;
3745  ESL_LAYER * pLayer;
3746  ESL_PACKET * pPacket;
3747  ESL_PORT * pPreviousPort;
3748  ESL_SERVICE * pService;
3749  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
3750  CONST ESL_SOCKET_BINDING * pSocketBinding;
3751  ESL_SOCKET * pSocket;
3752  EFI_STATUS Status;
3753
3754  DBG_ENTER ( );
3755
3756  //
3757  //  Verify the socket layer synchronization
3758  //
3759  VERIFY_TPL ( TPL_SOCKETS );
3760
3761  //
3762  //  Locate the port in the socket list
3763  //
3764  Status = EFI_SUCCESS;
3765  pLayer = &mEslLayer;
3766  DebugFlags = pPort->DebugFlags;
3767  pSocket = pPort->pSocket;
3768  pPreviousPort = pSocket->pPortList;
3769  if ( pPreviousPort == pPort ) {
3770    //
3771    //  Remove this port from the head of the socket list
3772    //
3773    pSocket->pPortList = pPort->pLinkSocket;
3774  }
3775  else {
3776    //
3777    //  Locate the port in the middle of the socket list
3778    //
3779    while (( NULL != pPreviousPort )
3780      && ( pPreviousPort->pLinkSocket != pPort )) {
3781      pPreviousPort = pPreviousPort->pLinkSocket;
3782    }
3783    if ( NULL != pPreviousPort ) {
3784      //
3785      //  Remove the port from the middle of the socket list
3786      //
3787      pPreviousPort->pLinkSocket = pPort->pLinkSocket;
3788    }
3789  }
3790
3791  //
3792  //  Locate the port in the service list
3793  //  Note that the port may not be in the service list
3794  //  if the service has been shutdown.
3795  //
3796  pService = pPort->pService;
3797  if ( NULL != pService ) {
3798    pPreviousPort = pService->pPortList;
3799    if ( pPreviousPort == pPort ) {
3800      //
3801      //  Remove this port from the head of the service list
3802      //
3803      pService->pPortList = pPort->pLinkService;
3804    }
3805    else {
3806      //
3807      //  Locate the port in the middle of the service list
3808      //
3809      while (( NULL != pPreviousPort )
3810        && ( pPreviousPort->pLinkService != pPort )) {
3811        pPreviousPort = pPreviousPort->pLinkService;
3812      }
3813      if ( NULL != pPreviousPort ) {
3814        //
3815        //  Remove the port from the middle of the service list
3816        //
3817        pPreviousPort->pLinkService = pPort->pLinkService;
3818      }
3819    }
3820  }
3821
3822  //
3823  //  Empty the urgent receive queue
3824  //
3825  while ( NULL != pSocket->pRxOobPacketListHead ) {
3826    pPacket = pSocket->pRxOobPacketListHead;
3827    pSocket->pRxOobPacketListHead = pPacket->pNext;
3828    pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
3829    EslSocketPacketFree ( pPacket, DEBUG_RX );
3830  }
3831  pSocket->pRxOobPacketListTail = NULL;
3832  ASSERT ( 0 == pSocket->RxOobBytes );
3833
3834  //
3835  //  Empty the receive queue
3836  //
3837  while ( NULL != pSocket->pRxPacketListHead ) {
3838    pPacket = pSocket->pRxPacketListHead;
3839    pSocket->pRxPacketListHead = pPacket->pNext;
3840    pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
3841    EslSocketPacketFree ( pPacket, DEBUG_RX );
3842  }
3843  pSocket->pRxPacketListTail = NULL;
3844  ASSERT ( 0 == pSocket->RxBytes );
3845
3846  //
3847  //  Empty the receive free queue
3848  //
3849  while ( NULL != pSocket->pRxFree ) {
3850    pPacket = pSocket->pRxFree;
3851    pSocket->pRxFree = pPacket->pNext;
3852    EslSocketPacketFree ( pPacket, DEBUG_RX );
3853  }
3854
3855  //
3856  //  Release the network specific resources
3857  //
3858  if ( NULL != pSocket->pApi->pfnPortClose ) {
3859    Status = pSocket->pApi->pfnPortClose ( pPort );
3860  }
3861
3862  //
3863  //  Done with the normal transmit events
3864  //
3865  Status = EslSocketIoFree ( pPort,
3866                             &pPort->pTxFree,
3867                             DebugFlags | DEBUG_POOL,
3868                             "normal transmit" );
3869
3870  //
3871  //  Done with the urgent transmit events
3872  //
3873  Status = EslSocketIoFree ( pPort,
3874                             &pPort->pTxOobFree,
3875                             DebugFlags | DEBUG_POOL,
3876                             "urgent transmit" );
3877
3878  //
3879  //  Done with the receive events
3880  //
3881  Status = EslSocketIoFree ( pPort,
3882                             &pPort->pRxFree,
3883                             DebugFlags | DEBUG_POOL,
3884                             "receive" );
3885
3886  //
3887  //  Done with the lower layer network protocol
3888  //
3889  pSocketBinding = pPort->pSocketBinding;
3890  if ( NULL != pPort->pProtocol.v ) {
3891    Status = gBS->CloseProtocol ( pPort->Handle,
3892                                  pSocketBinding->pNetworkProtocolGuid,
3893                                  pLayer->ImageHandle,
3894                                  NULL );
3895    if ( !EFI_ERROR ( Status )) {
3896      DEBUG (( DebugFlags,
3897                "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
3898                pPort->pProtocol.v,
3899                pPort->Handle ));
3900    }
3901    else {
3902      DEBUG (( DEBUG_ERROR | DebugFlags,
3903                "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
3904                pPort->Handle,
3905                Status ));
3906      ASSERT ( EFI_SUCCESS == Status );
3907    }
3908  }
3909
3910  //
3911  //  Done with the network port
3912  //
3913  pServiceBinding = pPort->pServiceBinding;
3914  if ( NULL != pPort->Handle ) {
3915    Status = pServiceBinding->DestroyChild ( pServiceBinding,
3916                                             pPort->Handle );
3917    if ( !EFI_ERROR ( Status )) {
3918      DEBUG (( DebugFlags | DEBUG_POOL,
3919                "0x%08x: %s port handle destroyed\r\n",
3920                pPort->Handle,
3921                pSocketBinding->pName ));
3922    }
3923    else {
3924      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
3925                "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
3926                pSocketBinding->pName,
3927                Status ));
3928      ASSERT ( EFI_SUCCESS == Status );
3929    }
3930  }
3931
3932  //
3933  //  Release the port structure
3934  //
3935  Status = gBS->FreePool ( pPort );
3936  if ( !EFI_ERROR ( Status )) {
3937    DEBUG (( DebugFlags | DEBUG_POOL,
3938              "0x%08x: Free pPort, %d bytes\r\n",
3939              pPort,
3940              sizeof ( *pPort )));
3941  }
3942  else {
3943    DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
3944              "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
3945              pPort,
3946              Status ));
3947    ASSERT ( EFI_SUCCESS == Status );
3948  }
3949
3950  //
3951  //  Mark the socket as closed if necessary
3952  //
3953  if ( NULL == pSocket->pPortList ) {
3954    pSocket->State = SOCKET_STATE_CLOSED;
3955    DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
3956              "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
3957              pSocket ));
3958  }
3959
3960  //
3961  //  Return the operation status
3962  //
3963  DBG_EXIT_STATUS ( Status );
3964  return Status;
3965}
3966
3967
3968/** Port close state 3.
3969
3970  This routine attempts to complete the port close operation.
3971
3972  This routine is called by the TCP layer upon completion of
3973  the close operation and by ::EslSocketPortCloseTxDone.
3974  See the \ref PortCloseStateMachine section.
3975
3976  @param[in]  Event     The close completion event
3977  @param[in]  pPort     Address of an ::ESL_PORT structure.
3978**/
3979VOID
3980EslSocketPortCloseComplete (
3981  IN EFI_EVENT Event,
3982  IN ESL_PORT * pPort
3983  )
3984{
3985  ESL_IO_MGMT * pIo;
3986  EFI_STATUS Status;
3987
3988  DBG_ENTER ( );
3989  VERIFY_AT_TPL ( TPL_SOCKETS );
3990
3991  //  Update the port state
3992  pPort->State = PORT_STATE_CLOSE_DONE;
3993  DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
3994            "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
3995            pPort ));
3996
3997  //  Shutdown the receive operation on the port
3998  if ( NULL != pPort->pfnRxCancel ) {
3999    pIo = pPort->pRxActive;
4000    while ( NULL != pIo ) {
4001      EslSocketRxCancel ( pPort, pIo );
4002      pIo = pIo->pNext;
4003    }
4004  }
4005
4006  //  Determine if the receive operation is pending
4007  Status = EslSocketPortCloseRxDone ( pPort );
4008  DBG_EXIT_STATUS ( Status );
4009  --Status;
4010}
4011
4012
4013/** Port close state 4.
4014
4015  This routine determines the state of the receive operations and
4016  continues the close operation after the pending receive operations
4017  are cancelled.
4018
4019  This routine is called by
4020  <ul>
4021    <li>::EslSocketPortCloseComplete</li>
4022    <li>::EslSocketPortCloseTxDone</li>
4023    <li>::EslSocketRxComplete</li>
4024  </ul>
4025  to determine the state of the receive operations.
4026  See the \ref PortCloseStateMachine section.
4027
4028  @param[in]  pPort       Address of an ::ESL_PORT structure.
4029
4030  @retval EFI_SUCCESS         The port is closed
4031  @retval EFI_NOT_READY       The port is still closing
4032  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4033                              most likely the routine was called already.
4034**/
4035EFI_STATUS
4036EslSocketPortCloseRxDone (
4037  IN ESL_PORT * pPort
4038  )
4039{
4040  EFI_STATUS Status;
4041
4042  DBG_ENTER ( );
4043
4044  //
4045  //  Verify the socket layer synchronization
4046  //
4047  VERIFY_TPL ( TPL_SOCKETS );
4048
4049  //
4050  //  Verify that the port is closing
4051  //
4052  Status = EFI_ALREADY_STARTED;
4053  if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
4054    //
4055    //  Determine if the receive operation is pending
4056    //
4057    Status = EFI_NOT_READY;
4058    if ( NULL == pPort->pRxActive ) {
4059      //
4060      //  The receive operation is complete
4061      //  Update the port state
4062      //
4063      pPort->State = PORT_STATE_CLOSE_RX_DONE;
4064      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4065                "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4066                pPort ));
4067
4068      //
4069      //  Complete the port close operation
4070      //
4071      Status = EslSocketPortClose ( pPort );
4072    }
4073    else {
4074      DEBUG_CODE_BEGIN ();
4075      {
4076        ESL_IO_MGMT * pIo;
4077        //
4078        //  Display the outstanding receive operations
4079        //
4080        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4081                  "0x%08x: Port Close: Receive still pending!\r\n",
4082                  pPort ));
4083        pIo = pPort->pRxActive;
4084        while ( NULL != pIo ) {
4085          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4086                    "0x%08x: Packet pending on network adapter\r\n",
4087                    pIo->pPacket ));
4088          pIo = pIo->pNext;
4089        }
4090      }
4091      DEBUG_CODE_END ( );
4092    }
4093  }
4094
4095  //
4096  //  Return the operation status
4097  //
4098  DBG_EXIT_STATUS ( Status );
4099  return Status;
4100}
4101
4102
4103/** Start the close operation on a port, state 1.
4104
4105  This routine marks the port as closed and initiates the \ref
4106  PortCloseStateMachine. The first step is to allow the \ref
4107  TransmitEngine to run down.
4108
4109  This routine is called by ::EslSocketCloseStart to initiate the socket
4110  network specific close operation on the socket.
4111
4112  @param[in]  pPort       Address of an ::ESL_PORT structure.
4113  @param[in]  bCloseNow   Set TRUE to abort active transfers
4114  @param[in]  DebugFlags  Flags for debug messages
4115
4116  @retval EFI_SUCCESS         The port is closed, not normally returned
4117  @retval EFI_NOT_READY       The port has started the closing process
4118  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4119                              most likely the routine was called already.
4120**/
4121EFI_STATUS
4122EslSocketPortCloseStart (
4123  IN ESL_PORT * pPort,
4124  IN BOOLEAN bCloseNow,
4125  IN UINTN DebugFlags
4126  )
4127{
4128  ESL_SOCKET * pSocket;
4129  EFI_STATUS Status;
4130
4131  DBG_ENTER ( );
4132
4133  //
4134  //  Verify the socket layer synchronization
4135  //
4136  VERIFY_TPL ( TPL_SOCKETS );
4137
4138  //
4139  //  Mark the port as closing
4140  //
4141  Status = EFI_ALREADY_STARTED;
4142  pSocket = pPort->pSocket;
4143  pSocket->errno = EALREADY;
4144  if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
4145
4146    //
4147    //  Update the port state
4148    //
4149    pPort->State = PORT_STATE_CLOSE_STARTED;
4150    DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4151              "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4152              pPort ));
4153    pPort->bCloseNow = bCloseNow;
4154    pPort->DebugFlags = DebugFlags;
4155
4156    //
4157    //  Determine if transmits are complete
4158    //
4159    Status = EslSocketPortCloseTxDone ( pPort );
4160  }
4161
4162  //
4163  //  Return the operation status
4164  //
4165  DBG_EXIT_STATUS ( Status );
4166  return Status;
4167}
4168
4169
4170/** Port close state 2.
4171
4172  This routine determines the state of the transmit engine and
4173  continue the close operation after the transmission is complete.
4174  The next step is to stop the \ref ReceiveEngine.
4175  See the \ref PortCloseStateMachine section.
4176
4177  This routine is called by ::EslSocketPortCloseStart to determine
4178  if the transmission is complete.
4179
4180  @param[in]  pPort           Address of an ::ESL_PORT structure.
4181
4182  @retval EFI_SUCCESS         The port is closed, not normally returned
4183  @retval EFI_NOT_READY       The port is still closing
4184  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4185                              most likely the routine was called already.
4186
4187**/
4188EFI_STATUS
4189EslSocketPortCloseTxDone (
4190  IN ESL_PORT * pPort
4191  )
4192{
4193  ESL_IO_MGMT * pIo;
4194  ESL_SOCKET * pSocket;
4195  EFI_STATUS Status;
4196
4197  DBG_ENTER ( );
4198
4199  //
4200  //  Verify the socket layer synchronization
4201  //
4202  VERIFY_TPL ( TPL_SOCKETS );
4203
4204  //
4205  //  All transmissions are complete or must be stopped
4206  //  Mark the port as TX complete
4207  //
4208  Status = EFI_ALREADY_STARTED;
4209  if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
4210    //
4211    //  Verify that the transmissions are complete
4212    //
4213    pSocket = pPort->pSocket;
4214    if ( pPort->bCloseNow
4215         || ( EFI_SUCCESS != pSocket->TxError )
4216         || (( NULL == pPort->pTxActive )
4217                && ( NULL == pPort->pTxOobActive ))) {
4218      //
4219      //  Update the port state
4220      //
4221      pPort->State = PORT_STATE_CLOSE_TX_DONE;
4222      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4223                "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4224                pPort ));
4225
4226      //
4227      //  Close the port
4228      //  Skip the close operation if the port is not configured
4229      //
4230      Status = EFI_SUCCESS;
4231      pSocket = pPort->pSocket;
4232      if (( pPort->bConfigured )
4233        && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
4234          //
4235          //  Start the close operation
4236          //
4237          Status = pSocket->pApi->pfnPortCloseOp ( pPort );
4238          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4239                    "0x%08x: Port Close: Close operation still pending!\r\n",
4240                    pPort ));
4241          ASSERT ( EFI_SUCCESS == Status );
4242      }
4243      else {
4244        //
4245        //  The receive operation is complete
4246        //  Update the port state
4247        //
4248        EslSocketPortCloseComplete ( NULL, pPort );
4249      }
4250    }
4251    else {
4252      //
4253      //  Transmissions are still active, exit
4254      //
4255      Status = EFI_NOT_READY;
4256      pSocket->errno = EAGAIN;
4257      DEBUG_CODE_BEGIN ( );
4258      {
4259        ESL_PACKET * pPacket;
4260
4261        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4262                  "0x%08x: Port Close: Transmits are still pending!\r\n",
4263                  pPort ));
4264
4265        //
4266        //  Display the pending urgent transmit packets
4267        //
4268        pPacket = pSocket->pTxOobPacketListHead;
4269        while ( NULL != pPacket ) {
4270          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4271                    "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4272                    pPacket,
4273                    pPacket->PacketSize ));
4274          pPacket = pPacket->pNext;
4275        }
4276
4277        pIo = pPort->pTxOobActive;
4278        while ( NULL != pIo ) {
4279          pPacket = pIo->pPacket;
4280          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4281                    "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4282                    pPacket,
4283                    pPacket->PacketSize,
4284                    pIo ));
4285          pIo = pIo->pNext;
4286        }
4287
4288        //
4289        //  Display the pending normal transmit packets
4290        //
4291        pPacket = pSocket->pTxPacketListHead;
4292        while ( NULL != pPacket ) {
4293          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4294                    "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4295                    pPacket,
4296                    pPacket->PacketSize ));
4297          pPacket = pPacket->pNext;
4298        }
4299
4300        pIo = pPort->pTxActive;
4301        while ( NULL != pIo ) {
4302          pPacket = pIo->pPacket;
4303          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4304                    "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4305                    pPacket,
4306                    pPacket->PacketSize,
4307                    pIo ));
4308          pIo = pIo->pNext;
4309        }
4310      }
4311      DEBUG_CODE_END ();
4312    }
4313  }
4314
4315  //
4316  //  Return the operation status
4317  //
4318  DBG_EXIT_STATUS ( Status );
4319  return Status;
4320}
4321
4322
4323/** Receive data from a network connection.
4324
4325  This routine calls the network specific routine to remove the
4326  next portion of data from the receive queue and return it to the
4327  caller.
4328
4329  The ::recvfrom routine calls this routine to determine if any data
4330  is received from the remote system.  Note that the other routines
4331  ::recv and ::read are layered on top of ::recvfrom.
4332
4333  @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4334  @param[in]      Flags           Message control flags
4335  @param[in]      BufferLength    Length of the the buffer
4336  @param[in]      pBuffer         Address of a buffer to receive the data.
4337  @param[in]      pDataLength     Number of received data bytes in the buffer.
4338  @param[out]     pAddress        Network address to receive the remote system address
4339  @param[in,out]  pAddressLength  Length of the remote network address structure
4340  @param[out]     pErrno          Address to receive the errno value upon completion.
4341
4342  @retval EFI_SUCCESS - Socket data successfully received
4343**/
4344EFI_STATUS
4345EslSocketReceive (
4346  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
4347  IN INT32 Flags,
4348  IN size_t BufferLength,
4349  IN UINT8 * pBuffer,
4350  OUT size_t * pDataLength,
4351  OUT struct sockaddr * pAddress,
4352  IN OUT socklen_t * pAddressLength,
4353  IN int * pErrno
4354  )
4355{
4356  union {
4357    struct sockaddr_in v4;
4358    struct sockaddr_in6 v6;
4359  } Addr;
4360  socklen_t AddressLength;
4361  BOOLEAN bConsumePacket;
4362  BOOLEAN bUrgentQueue;
4363  size_t DataLength;
4364  ESL_PACKET * pNextPacket;
4365  ESL_PACKET * pPacket;
4366  ESL_PORT * pPort;
4367  ESL_PACKET ** ppQueueHead;
4368  ESL_PACKET ** ppQueueTail;
4369  struct sockaddr * pRemoteAddress;
4370  size_t * pRxDataBytes;
4371  ESL_SOCKET * pSocket;
4372  size_t SkipBytes;
4373  EFI_STATUS Status;
4374  EFI_TPL TplPrevious;
4375
4376  DBG_ENTER ( );
4377
4378  //
4379  //  Assume success
4380  //
4381  Status = EFI_SUCCESS;
4382
4383  //
4384  //  Validate the socket
4385  //
4386  pSocket = NULL;
4387  if ( NULL != pSocketProtocol ) {
4388    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
4389
4390    //
4391    //  Validate the return address parameters
4392    //
4393    if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
4394      //
4395      //  Return the transmit error if necessary
4396      //
4397      if ( EFI_SUCCESS != pSocket->TxError ) {
4398        pSocket->errno = EIO;
4399        Status = pSocket->TxError;
4400        pSocket->TxError = EFI_SUCCESS;
4401      }
4402      else {
4403        //
4404        //  Verify the socket state
4405        //
4406        Status = EslSocketIsConfigured ( pSocket );
4407        if ( !EFI_ERROR ( Status )) {
4408          //
4409          //  Validate the buffer length
4410          //
4411          if (( NULL == pDataLength )
4412            || ( NULL == pBuffer )) {
4413            if ( NULL == pDataLength ) {
4414              DEBUG (( DEBUG_RX,
4415                        "ERROR - pDataLength is NULL!\r\n" ));
4416            }
4417            else {
4418              DEBUG (( DEBUG_RX,
4419                        "ERROR - pBuffer is NULL!\r\n" ));
4420            }
4421            Status = EFI_INVALID_PARAMETER;
4422            pSocket->errno = EFAULT;
4423          }
4424          else {
4425            //
4426            //  Verify the API
4427            //
4428            if ( NULL == pSocket->pApi->pfnReceive ) {
4429              Status = EFI_UNSUPPORTED;
4430              pSocket->errno = ENOTSUP;
4431            }
4432            else {
4433              //
4434              //  Zero the receive address if being returned
4435              //
4436              pRemoteAddress = NULL;
4437              if ( NULL != pAddress ) {
4438                pRemoteAddress = (struct sockaddr *)&Addr;
4439                ZeroMem ( pRemoteAddress, sizeof ( Addr ));
4440                pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
4441                pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
4442              }
4443
4444              //
4445              //  Synchronize with the socket layer
4446              //
4447              RAISE_TPL ( TplPrevious, TPL_SOCKETS );
4448
4449              //
4450              //  Assume failure
4451              //
4452              Status = EFI_UNSUPPORTED;
4453              pSocket->errno = ENOTCONN;
4454
4455              //
4456              //  Verify that the socket is connected
4457              //
4458              if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
4459                //
4460                //  Poll the network to increase performance
4461                //
4462                EslSocketRxPoll ( pSocket );
4463
4464                //
4465                //  Locate the port
4466                //
4467                pPort = pSocket->pPortList;
4468                if ( NULL != pPort ) {
4469                  //
4470                  //  Determine the queue head
4471                  //
4472                  bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
4473                  if ( bUrgentQueue ) {
4474                    ppQueueHead = &pSocket->pRxOobPacketListHead;
4475                    ppQueueTail = &pSocket->pRxOobPacketListTail;
4476                    pRxDataBytes = &pSocket->RxOobBytes;
4477                  }
4478                  else {
4479                    ppQueueHead = &pSocket->pRxPacketListHead;
4480                    ppQueueTail = &pSocket->pRxPacketListTail;
4481                    pRxDataBytes = &pSocket->RxBytes;
4482                  }
4483
4484                  //
4485                  //  Determine if there is any data on the queue
4486                  //
4487                  *pDataLength = 0;
4488                  pPacket = *ppQueueHead;
4489                  if ( NULL != pPacket ) {
4490                    //
4491                    //  Copy the received data
4492                    //
4493                    do {
4494                      //
4495                      //  Attempt to receive a packet
4496                      //
4497                      SkipBytes = 0;
4498                      bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
4499                      pBuffer = pSocket->pApi->pfnReceive ( pPort,
4500                                                            pPacket,
4501                                                            &bConsumePacket,
4502                                                            BufferLength,
4503                                                            pBuffer,
4504                                                            &DataLength,
4505                                                            (struct sockaddr *)&Addr,
4506                                                            &SkipBytes );
4507                      *pDataLength += DataLength;
4508                      BufferLength -= DataLength;
4509
4510                      //
4511                      //  Determine if the data is being read
4512                      //
4513                      pNextPacket = pPacket->pNext;
4514                      if ( bConsumePacket ) {
4515                        //
4516                        //  All done with this packet
4517                        //  Account for any discarded data
4518                        //
4519                        pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
4520                        if ( 0 != SkipBytes ) {
4521                          DEBUG (( DEBUG_RX,
4522                                    "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4523                                    pPort,
4524                                    SkipBytes ));
4525                        }
4526
4527                        //
4528                        //  Remove this packet from the queue
4529                        //
4530                        *ppQueueHead = pPacket->pNext;
4531                        if ( NULL == *ppQueueHead ) {
4532                          *ppQueueTail = NULL;
4533                        }
4534
4535                        //
4536                        //  Move the packet to the free queue
4537                        //
4538                        pPacket->pNext = pSocket->pRxFree;
4539                        pSocket->pRxFree = pPacket;
4540                        DEBUG (( DEBUG_RX,
4541                                  "0x%08x: Port freeing packet 0x%08x\r\n",
4542                                  pPort,
4543                                  pPacket ));
4544
4545                        //
4546                        //  Restart the receive operation if necessary
4547                        //
4548                        if (( NULL != pPort->pRxFree )
4549                          && ( MAX_RX_DATA > pSocket->RxBytes )) {
4550                            EslSocketRxStart ( pPort );
4551                        }
4552                      }
4553
4554                      //
4555                      //  Get the next packet
4556                      //
4557                      pPacket = pNextPacket;
4558                    } while (( SOCK_STREAM == pSocket->Type )
4559                          && ( NULL != pPacket )
4560                          && ( 0 < BufferLength ));
4561
4562                    //
4563                    //  Successful operation
4564                    //
4565                    Status = EFI_SUCCESS;
4566                    pSocket->errno = 0;
4567                  }
4568                  else {
4569                    //
4570                    //  The queue is empty
4571                    //  Determine if it is time to return the receive error
4572                    //
4573                    if ( EFI_ERROR ( pSocket->RxError )
4574                      && ( NULL == pSocket->pRxPacketListHead )
4575                      && ( NULL == pSocket->pRxOobPacketListHead )) {
4576                      Status = pSocket->RxError;
4577                      pSocket->RxError = EFI_SUCCESS;
4578                      switch ( Status ) {
4579                      default:
4580                        pSocket->errno = EIO;
4581                        break;
4582
4583                      case EFI_CONNECTION_FIN:
4584                        //
4585                        //  Continue to return zero bytes received when the
4586                        //  peer has successfully closed the connection
4587                        //
4588                        pSocket->RxError = EFI_CONNECTION_FIN;
4589                        *pDataLength = 0;
4590                        pSocket->errno = 0;
4591                        Status = EFI_SUCCESS;
4592                        break;
4593
4594                      case EFI_CONNECTION_REFUSED:
4595                        pSocket->errno = ECONNREFUSED;
4596                        break;
4597
4598                      case EFI_CONNECTION_RESET:
4599                        pSocket->errno = ECONNRESET;
4600                        break;
4601
4602                      case EFI_HOST_UNREACHABLE:
4603                        pSocket->errno = EHOSTUNREACH;
4604                        break;
4605
4606                      case EFI_NETWORK_UNREACHABLE:
4607                        pSocket->errno = ENETUNREACH;
4608                        break;
4609
4610                      case EFI_PORT_UNREACHABLE:
4611                        pSocket->errno = EPROTONOSUPPORT;
4612                        break;
4613
4614                      case EFI_PROTOCOL_UNREACHABLE:
4615                        pSocket->errno = ENOPROTOOPT;
4616                        break;
4617                      }
4618                    }
4619                    else {
4620                      Status = EFI_NOT_READY;
4621                      pSocket->errno = EAGAIN;
4622                    }
4623                  }
4624                }
4625              }
4626
4627              //
4628              //  Release the socket layer synchronization
4629              //
4630              RESTORE_TPL ( TplPrevious );
4631
4632              if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
4633                //
4634                //  Return the remote address if requested, truncate if necessary
4635                //
4636                AddressLength = pRemoteAddress->sa_len;
4637                if ( AddressLength > *pAddressLength ) {
4638                  AddressLength = *pAddressLength;
4639                }
4640                DEBUG (( DEBUG_RX,
4641                          "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
4642                ZeroMem ( pAddress, *pAddressLength );
4643                CopyMem ( pAddress, &Addr, AddressLength );
4644
4645                //
4646                //  Update the address length
4647                //
4648                *pAddressLength = pRemoteAddress->sa_len;
4649              }
4650            }
4651          }
4652        }
4653      }
4654
4655
4656    }
4657    else {
4658      //
4659      //  Bad return address pointer and length
4660      //
4661      Status = EFI_INVALID_PARAMETER;
4662      pSocket->errno = EINVAL;
4663    }
4664  }
4665
4666  //
4667  //  Return the operation status
4668  //
4669  if ( NULL != pErrno ) {
4670    if ( NULL != pSocket ) {
4671      *pErrno = pSocket->errno;
4672    }
4673    else {
4674      Status = EFI_INVALID_PARAMETER;
4675      *pErrno = ENOTSOCK;
4676    }
4677  }
4678  DBG_EXIT_STATUS ( Status );
4679  return Status;
4680}
4681
4682
4683/** Cancel the receive operations.
4684
4685  This routine cancels a pending receive operation.
4686  See the \ref ReceiveEngine section.
4687
4688  This routine is called by ::EslSocketShutdown when the socket
4689  layer is being shutdown.
4690
4691  @param[in]  pPort     Address of an ::ESL_PORT structure
4692  @param[in]  pIo       Address of an ::ESL_IO_MGMT structure
4693**/
4694VOID
4695EslSocketRxCancel (
4696  IN ESL_PORT * pPort,
4697  IN ESL_IO_MGMT * pIo
4698  )
4699{
4700  EFI_STATUS Status;
4701
4702  DBG_ENTER ( );
4703
4704  //
4705  //  Cancel the outstanding receive
4706  //
4707  Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
4708                                &pIo->Token );
4709  if ( !EFI_ERROR ( Status )) {
4710    DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
4711              "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4712              pIo->pPacket,
4713              pPort ));
4714  }
4715  else {
4716    DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
4717              "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4718              pIo->pPacket,
4719              pPort,
4720              Status ));
4721  }
4722  DBG_EXIT ( );
4723}
4724
4725
4726/** Process the receive completion.
4727
4728  This routine queues the data in FIFO order in either the urgent
4729  or normal data queues depending upon the type of data received.
4730  See the \ref ReceiveEngine section.
4731
4732  This routine is called when some data is received by:
4733  <ul>
4734    <li>::EslIp4RxComplete</li>
4735    <li>::EslTcp4RxComplete</li>
4736    <li>::EslUdp4RxComplete</li>
4737  </ul>
4738
4739  @param[in]  pIo           Address of an ::ESL_IO_MGMT structure
4740  @param[in]  Status        Receive status
4741  @param[in]  LengthInBytes Length of the receive data
4742  @param[in]  bUrgent       TRUE if urgent data is received and FALSE
4743                            for normal data.
4744**/
4745VOID
4746EslSocketRxComplete (
4747  IN ESL_IO_MGMT * pIo,
4748  IN EFI_STATUS Status,
4749  IN UINTN LengthInBytes,
4750  IN BOOLEAN bUrgent
4751  )
4752{
4753  BOOLEAN bUrgentQueue;
4754  ESL_IO_MGMT * pIoNext;
4755  ESL_PACKET * pPacket;
4756  ESL_PORT * pPort;
4757  ESL_PACKET * pPrevious;
4758  ESL_PACKET ** ppQueueHead;
4759  ESL_PACKET ** ppQueueTail;
4760  size_t * pRxBytes;
4761  ESL_SOCKET * pSocket;
4762
4763  DBG_ENTER ( );
4764  VERIFY_AT_TPL ( TPL_SOCKETS );
4765
4766  //
4767  //  Locate the active receive packet
4768  //
4769  pPacket = pIo->pPacket;
4770  pPort = pIo->pPort;
4771  pSocket = pPort->pSocket;
4772
4773  //
4774  //         pPort->pRxActive
4775  //                |
4776  //                V
4777  //          +-------------+   +-------------+   +-------------+
4778  //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4779  //          +-------------+   +-------------+   +-------------+
4780  //
4781  //          +-------------+   +-------------+   +-------------+
4782  //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4783  //          +-------------+   +-------------+   +-------------+
4784  //                ^
4785  //                |
4786  //          pPort->pRxFree
4787  //
4788  //
4789  //  Remove the IO structure from the active list
4790  //  The following code searches for the entry in the list and does not
4791  //  assume that the receive operations complete in the order they were
4792  //  issued to the UEFI network layer.
4793  //
4794  pIoNext = pPort->pRxActive;
4795  while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
4796  {
4797    pIoNext = pIoNext->pNext;
4798  }
4799  ASSERT ( NULL != pIoNext );
4800  if ( pIoNext == pIo ) {
4801    pPort->pRxActive = pIo->pNext;  //  Beginning of list
4802  }
4803  else {
4804    pIoNext->pNext = pIo->pNext;    //  Middle of list
4805  }
4806
4807  //
4808  //  Free the IO structure
4809  //
4810  pIo->pNext = pPort->pRxFree;
4811  pPort->pRxFree = pIo;
4812
4813  //
4814  //            pRxOobPacketListHead              pRxOobPacketListTail
4815  //                      |                                 |
4816  //                      V                                 V
4817  //               +------------+   +------------+   +------------+
4818  //  Urgent Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4819  //               +------------+   +------------+   +------------+
4820  //
4821  //               +------------+   +------------+   +------------+
4822  //  Normal Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4823  //               +------------+   +------------+   +------------+
4824  //                      ^                                 ^
4825  //                      |                                 |
4826  //              pRxPacketListHead                pRxPacketListTail
4827  //
4828  //
4829  //  Determine the queue to use
4830  //
4831  bUrgentQueue = (BOOLEAN)( bUrgent
4832               && pSocket->pApi->bOobSupported
4833               && ( !pSocket->bOobInLine ));
4834  if ( bUrgentQueue ) {
4835    ppQueueHead = &pSocket->pRxOobPacketListHead;
4836    ppQueueTail = &pSocket->pRxOobPacketListTail;
4837    pRxBytes = &pSocket->RxOobBytes;
4838  }
4839  else {
4840    ppQueueHead = &pSocket->pRxPacketListHead;
4841    ppQueueTail = &pSocket->pRxPacketListTail;
4842    pRxBytes = &pSocket->RxBytes;
4843  }
4844
4845  //
4846  //  Determine if this receive was successful
4847  //
4848  if (( !EFI_ERROR ( Status ))
4849    && ( PORT_STATE_CLOSE_STARTED > pPort->State )
4850    && ( !pSocket->bRxDisable )) {
4851    //
4852    //  Account for the received data
4853    //
4854    *pRxBytes += LengthInBytes;
4855
4856    //
4857    //  Log the received data
4858    //
4859    DEBUG (( DEBUG_RX | DEBUG_INFO,
4860              "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4861              pPacket,
4862              bUrgentQueue ? L"urgent" : L"normal",
4863              pPort,
4864              LengthInBytes,
4865              bUrgent ? L"urgent" : L"normal" ));
4866
4867    //
4868    //  Add the packet to the list tail.
4869    //
4870    pPacket->pNext = NULL;
4871    pPrevious = *ppQueueTail;
4872    if ( NULL == pPrevious ) {
4873      *ppQueueHead = pPacket;
4874    }
4875    else {
4876      pPrevious->pNext = pPacket;
4877    }
4878    *ppQueueTail = pPacket;
4879
4880    //
4881    //  Attempt to restart this receive operation
4882    //
4883    if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
4884      EslSocketRxStart ( pPort );
4885    }
4886    else {
4887      DEBUG (( DEBUG_RX,
4888                "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
4889                pPort,
4890                pSocket->RxBytes ));
4891    }
4892  }
4893  else {
4894    if ( EFI_ERROR ( Status )) {
4895        DEBUG (( DEBUG_RX | DEBUG_INFO,
4896                  "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
4897                  pPort,
4898                  pPacket,
4899                  Status ));
4900    }
4901
4902    //
4903    //  Account for the receive bytes and release the driver's buffer
4904    //
4905    if ( !EFI_ERROR ( Status )) {
4906      *pRxBytes += LengthInBytes;
4907      pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
4908    }
4909
4910    //
4911    //  Receive error, free the packet save the error
4912    //
4913    EslSocketPacketFree ( pPacket, DEBUG_RX );
4914    if ( !EFI_ERROR ( pSocket->RxError )) {
4915      pSocket->RxError = Status;
4916    }
4917
4918    //
4919    //  Update the port state
4920    //
4921    if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
4922      if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
4923        EslSocketPortCloseRxDone ( pPort );
4924      }
4925    }
4926    else {
4927      if ( EFI_ERROR ( Status )) {
4928        DEBUG (( DEBUG_RX | DEBUG_INFO,
4929                  "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
4930                  pPort,
4931                  Status ));
4932        pPort->State = PORT_STATE_RX_ERROR;
4933      }
4934    }
4935  }
4936
4937  DBG_EXIT ( );
4938}
4939
4940
4941/** Poll a socket for pending receive activity.
4942
4943  This routine is called at elivated TPL and extends the idle
4944  loop which polls a socket down into the LAN driver layer to
4945  determine if there is any receive activity.
4946
4947  The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
4948  routines call this routine when there is nothing to do.
4949
4950  @param[in]  pSocket   Address of an ::EFI_SOCKET structure.
4951 **/
4952VOID
4953EslSocketRxPoll (
4954  IN ESL_SOCKET * pSocket
4955  )
4956{
4957  ESL_PORT * pPort;
4958
4959  DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));
4960
4961  //
4962  //  Increase the network performance by extending the
4963  //  polling (idle) loop down into the LAN driver
4964  //
4965  pPort = pSocket->pPortList;
4966  while ( NULL != pPort ) {
4967    //
4968    //  Poll the LAN adapter
4969    //
4970    pPort->pfnRxPoll ( pPort->pProtocol.v );
4971
4972    //
4973    //  Locate the next LAN adapter
4974    //
4975    pPort = pPort->pLinkSocket;
4976  }
4977
4978  DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));
4979}
4980
4981
4982/** Start a receive operation.
4983
4984  This routine posts a receive buffer to the network adapter.
4985  See the \ref ReceiveEngine section.
4986
4987  This support routine is called by:
4988  <ul>
4989    <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
4990    <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4991    <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
4992    <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
4993    <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
4994    <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4995    <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
4996    <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4997    <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
4998  </ul>
4999
5000  @param[in]  pPort       Address of an ::ESL_PORT structure.
5001**/
5002VOID
5003EslSocketRxStart (
5004  IN ESL_PORT * pPort
5005  )
5006{
5007  UINT8 * pBuffer;
5008  ESL_IO_MGMT * pIo;
5009  ESL_PACKET * pPacket;
5010  ESL_SOCKET * pSocket;
5011  EFI_STATUS Status;
5012
5013  DBG_ENTER ( );
5014
5015  //
5016  //  Determine if a receive is already pending
5017  //
5018  Status = EFI_SUCCESS;
5019  pPacket = NULL;
5020  pSocket = pPort->pSocket;
5021  if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
5022    if (( NULL != pPort->pRxFree )
5023      && ( !pSocket->bRxDisable )
5024      && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
5025      //
5026      //  Start all of the pending receive operations
5027      //
5028      while ( NULL != pPort->pRxFree ) {
5029        //
5030        //  Determine if there are any free packets
5031        //
5032        pPacket = pSocket->pRxFree;
5033        if ( NULL != pPacket ) {
5034          //
5035          //  Remove this packet from the free list
5036          //
5037          pSocket->pRxFree = pPacket->pNext;
5038          DEBUG (( DEBUG_RX,
5039                    "0x%08x: Port removed packet 0x%08x from free list\r\n",
5040                    pPort,
5041                    pPacket ));
5042        }
5043        else {
5044          //
5045          //  Allocate a packet structure
5046          //
5047          Status = EslSocketPacketAllocate ( &pPacket,
5048                                             pSocket->pApi->RxPacketBytes,
5049                                             pSocket->pApi->RxZeroBytes,
5050                                             DEBUG_RX );
5051          if ( EFI_ERROR ( Status )) {
5052            pPacket = NULL;
5053            DEBUG (( DEBUG_ERROR | DEBUG_RX,
5054                      "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5055                      pPort,
5056                      Status ));
5057            break;
5058          }
5059        }
5060
5061        //
5062        //  Connect the IO and packet structures
5063        //
5064        pIo = pPort->pRxFree;
5065        pIo->pPacket = pPacket;
5066
5067        //
5068        //  Eliminate the need for IP4 and UDP4 specific routines by
5069        //  clearing the RX data pointer here.
5070        //
5071        //  No driver buffer for this packet
5072        //
5073        //    +--------------------+
5074        //    | ESL_IO_MGMT        |
5075        //    |                    |
5076        //    |    +---------------+
5077        //    |    | Token         |
5078        //    |    |        RxData --> NULL
5079        //    +----+---------------+
5080        //
5081        pBuffer = (UINT8 *)pIo;
5082        pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
5083        *(VOID **)pBuffer = NULL;
5084
5085        //
5086        //  Network specific receive packet initialization
5087        //
5088        if ( NULL != pSocket->pApi->pfnRxStart ) {
5089          pSocket->pApi->pfnRxStart ( pPort, pIo );
5090        }
5091
5092        //
5093        //  Start the receive on the packet
5094        //
5095        Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
5096        if ( !EFI_ERROR ( Status )) {
5097          DEBUG (( DEBUG_RX | DEBUG_INFO,
5098                    "0x%08x: Packet receive pending on port 0x%08x\r\n",
5099                    pPacket,
5100                    pPort ));
5101          //
5102          //  Allocate the receive control structure
5103          //
5104          pPort->pRxFree = pIo->pNext;
5105
5106          //
5107          //  Mark this receive as pending
5108          //
5109          pIo->pNext = pPort->pRxActive;
5110          pPort->pRxActive = pIo;
5111
5112        }
5113        else {
5114          DEBUG (( DEBUG_RX | DEBUG_INFO,
5115                    "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5116                    pPort,
5117                    Status ));
5118          if ( !EFI_ERROR ( pSocket->RxError )) {
5119            //
5120            //  Save the error status
5121            //
5122            pSocket->RxError = Status;
5123          }
5124
5125          //
5126          //  Free the packet
5127          //
5128          pIo->pPacket = NULL;
5129          pPacket->pNext = pSocket->pRxFree;
5130          pSocket->pRxFree = pPacket;
5131          break;
5132        }
5133      }
5134    }
5135    else {
5136      if ( NULL == pPort->pRxFree ) {
5137        DEBUG (( DEBUG_RX | DEBUG_INFO,
5138                  "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5139                  pPort));
5140      }
5141      if ( pSocket->bRxDisable ) {
5142        DEBUG (( DEBUG_RX | DEBUG_INFO,
5143                  "0x%08x: Port, receive disabled!\r\n",
5144                  pPort ));
5145      }
5146      if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
5147        DEBUG (( DEBUG_RX | DEBUG_INFO,
5148                  "0x%08x: Port, is closing!\r\n",
5149                  pPort ));
5150      }
5151    }
5152  }
5153  else {
5154    DEBUG (( DEBUG_ERROR | DEBUG_RX,
5155              "ERROR - Previous receive error, Status: %r\r\n",
5156               pPort->pSocket->RxError ));
5157  }
5158
5159  DBG_EXIT ( );
5160}
5161
5162
5163/** Shutdown the socket receive and transmit operations.
5164
5165  This routine sets a flag to stop future transmissions and calls
5166  the network specific layer to cancel the pending receive operation.
5167
5168  The ::shutdown routine calls this routine to stop receive and transmit
5169  operations on the socket.
5170
5171  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5172  @param[in]  How             Which operations to stop
5173  @param[out] pErrno          Address to receive the errno value upon completion.
5174
5175  @retval EFI_SUCCESS - Socket operations successfully shutdown
5176**/
5177EFI_STATUS
5178EslSocketShutdown (
5179  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
5180  IN int How,
5181  IN int * pErrno
5182  )
5183{
5184  ESL_IO_MGMT * pIo;
5185  ESL_PORT * pPort;
5186  ESL_SOCKET * pSocket;
5187  EFI_STATUS Status;
5188  EFI_TPL TplPrevious;
5189
5190  DBG_ENTER ( );
5191
5192  //
5193  //  Assume success
5194  //
5195  Status = EFI_SUCCESS;
5196
5197  //
5198  //  Validate the socket
5199  //
5200  pSocket = NULL;
5201  if ( NULL != pSocketProtocol ) {
5202    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
5203
5204    //
5205    //  Verify that the socket is connected
5206    //
5207    if ( pSocket->bConnected ) {
5208      //
5209      //  Validate the How value
5210      //
5211      if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {
5212        //
5213        //  Synchronize with the socket layer
5214        //
5215        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
5216
5217        //
5218        //  Disable the receiver if requested
5219        //
5220        if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {
5221          pSocket->bRxDisable = TRUE;
5222        }
5223
5224        //
5225        //  Disable the transmitter if requested
5226        //
5227        if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {
5228          pSocket->bTxDisable = TRUE;
5229        }
5230
5231        //
5232        //  Cancel the pending receive operations
5233        //
5234        if ( pSocket->bRxDisable ) {
5235          //
5236          //  Walk the list of ports
5237          //
5238          pPort = pSocket->pPortList;
5239          while ( NULL != pPort ) {
5240            //
5241            //  Walk the list of active receive operations
5242            //
5243            pIo = pPort->pRxActive;
5244            while ( NULL != pIo ) {
5245              EslSocketRxCancel ( pPort, pIo );
5246            }
5247
5248            //
5249            //  Set the next port
5250            //
5251            pPort = pPort->pLinkSocket;
5252          }
5253        }
5254
5255        //
5256        //  Release the socket layer synchronization
5257        //
5258        RESTORE_TPL ( TplPrevious );
5259      }
5260      else {
5261        //
5262        //  Invalid How value
5263        //
5264        pSocket->errno = EINVAL;
5265        Status = EFI_INVALID_PARAMETER;
5266      }
5267    }
5268    else {
5269      //
5270      //  The socket is not connected
5271      //
5272      pSocket->errno = ENOTCONN;
5273      Status = EFI_NOT_STARTED;
5274    }
5275  }
5276
5277  //
5278  //  Return the operation status
5279  //
5280  if ( NULL != pErrno ) {
5281    if ( NULL != pSocket ) {
5282      *pErrno = pSocket->errno;
5283    }
5284    else {
5285      Status = EFI_INVALID_PARAMETER;
5286      *pErrno = ENOTSOCK;
5287    }
5288  }
5289  DBG_EXIT_STATUS ( Status );
5290  return Status;
5291}
5292
5293
5294/** Send data using a network connection.
5295
5296  This routine calls the network specific layer to queue the data
5297  for transmission.  Eventually the buffer will reach the head of
5298  the queue and will get transmitted over the network by the
5299  \ref TransmitEngine.  For datagram
5300  sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5301  the data reaches the application running on the remote system.
5302
5303  The ::sendto routine calls this routine to send data to the remote
5304  system.  Note that ::send and ::write are layered on top of ::sendto.
5305
5306  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5307  @param[in]  Flags           Message control flags
5308  @param[in]  BufferLength    Length of the the buffer
5309  @param[in]  pBuffer         Address of a buffer containing the data to send
5310  @param[in]  pDataLength     Address to receive the number of data bytes sent
5311  @param[in]  pAddress        Network address of the remote system address
5312  @param[in]  AddressLength   Length of the remote network address structure
5313  @param[out] pErrno          Address to receive the errno value upon completion.
5314
5315  @retval EFI_SUCCESS - Socket data successfully queued for transmit
5316**/
5317EFI_STATUS
5318EslSocketTransmit (
5319  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
5320  IN int Flags,
5321  IN size_t BufferLength,
5322  IN CONST UINT8 * pBuffer,
5323  OUT size_t * pDataLength,
5324  IN const struct sockaddr * pAddress,
5325  IN socklen_t AddressLength,
5326  IN int * pErrno
5327  )
5328{
5329  ESL_SOCKET * pSocket;
5330  EFI_STATUS Status;
5331  EFI_TPL TplPrevious;
5332
5333  DBG_ENTER ( );
5334
5335  //
5336  //  Assume success
5337  //
5338  Status = EFI_SUCCESS;
5339
5340  //
5341  //  Validate the socket
5342  //
5343  pSocket = NULL;
5344  if ( NULL != pSocketProtocol ) {
5345    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
5346
5347    //
5348    //  Return the transmit error if necessary
5349    //
5350    if ( EFI_SUCCESS != pSocket->TxError ) {
5351      pSocket->errno = EIO;
5352      Status = pSocket->TxError;
5353      pSocket->TxError = EFI_SUCCESS;
5354    }
5355    else {
5356      //
5357      //  Verify the socket state
5358      //
5359      Status = EslSocketIsConfigured ( pSocket );
5360      if ( !EFI_ERROR ( Status )) {
5361        //
5362        //  Verify that transmit is still allowed
5363        //
5364        if ( !pSocket->bTxDisable ) {
5365          //
5366          //  Validate the buffer length
5367          //
5368          if (( NULL == pDataLength )
5369            && ( 0 > pDataLength )
5370            && ( NULL == pBuffer )) {
5371            if ( NULL == pDataLength ) {
5372              DEBUG (( DEBUG_RX,
5373                        "ERROR - pDataLength is NULL!\r\n" ));
5374            }
5375            else if ( NULL == pBuffer ) {
5376              DEBUG (( DEBUG_RX,
5377                        "ERROR - pBuffer is NULL!\r\n" ));
5378            }
5379            else {
5380              DEBUG (( DEBUG_RX,
5381                        "ERROR - Data length < 0!\r\n" ));
5382            }
5383            Status = EFI_INVALID_PARAMETER;
5384            pSocket->errno = EFAULT;
5385          }
5386          else {
5387            //
5388            //  Validate the remote network address
5389            //
5390            if (( NULL != pAddress )
5391              && ( AddressLength < pAddress->sa_len )) {
5392              DEBUG (( DEBUG_TX,
5393                        "ERROR - Invalid sin_len field in address\r\n" ));
5394              Status = EFI_INVALID_PARAMETER;
5395              pSocket->errno = EFAULT;
5396            }
5397            else {
5398              //
5399              //  Verify the API
5400              //
5401              if ( NULL == pSocket->pApi->pfnTransmit ) {
5402                Status = EFI_UNSUPPORTED;
5403                pSocket->errno = ENOTSUP;
5404              }
5405              else {
5406                //
5407                //  Synchronize with the socket layer
5408                //
5409                RAISE_TPL ( TplPrevious, TPL_SOCKETS );
5410
5411                //
5412                //  Poll the network to increase performance
5413                //
5414                EslSocketRxPoll ( pSocket );
5415
5416                //
5417                //  Attempt to buffer the packet for transmission
5418                //
5419                Status = pSocket->pApi->pfnTransmit ( pSocket,
5420                                                      Flags,
5421                                                      BufferLength,
5422                                                      pBuffer,
5423                                                      pDataLength,
5424                                                      pAddress,
5425                                                      AddressLength );
5426
5427                //
5428                //  Release the socket layer synchronization
5429                //
5430                RESTORE_TPL ( TplPrevious );
5431              }
5432            }
5433          }
5434        }
5435        else {
5436          //
5437          //  The transmitter was shutdown
5438          //
5439          pSocket->errno = EPIPE;
5440          Status = EFI_NOT_STARTED;
5441        }
5442      }
5443    }
5444  }
5445
5446  //
5447  //  Return the operation status
5448  //
5449  if ( NULL != pErrno ) {
5450    if ( NULL != pSocket ) {
5451      *pErrno = pSocket->errno;
5452    }
5453    else {
5454      Status = EFI_INVALID_PARAMETER;
5455      *pErrno = ENOTSOCK;
5456    }
5457  }
5458  DBG_EXIT_STATUS ( Status );
5459  return Status;
5460}
5461
5462
5463/** Complete the transmit operation.
5464
5465  This support routine handles the transmit completion processing for
5466  the various network layers.  It frees the ::ESL_IO_MGMT structure
5467  and and frees packet resources by calling ::EslSocketPacketFree.
5468  Transmit errors are logged in ESL_SOCKET::TxError.
5469  See the \ref TransmitEngine section.
5470
5471  This routine is called by:
5472  <ul>
5473    <li>::EslIp4TxComplete</li>
5474    <li>::EslTcp4TxComplete</li>
5475    <li>::EslTcp4TxOobComplete</li>
5476    <li>::EslUdp4TxComplete</li>
5477  </ul>
5478
5479  @param[in]  pIo             Address of an ::ESL_IO_MGMT structure
5480  @param[in]  LengthInBytes   Length of the data in bytes
5481  @param[in]  Status          Transmit operation status
5482  @param[in]  pQueueType      Zero terminated string describing queue type
5483  @param[in]  ppQueueHead     Transmit queue head address
5484  @param[in]  ppQueueTail     Transmit queue tail address
5485  @param[in]  ppActive        Active transmit queue address
5486  @param[in]  ppFree          Free transmit queue address
5487**/
5488VOID
5489EslSocketTxComplete (
5490  IN ESL_IO_MGMT * pIo,
5491  IN UINT32 LengthInBytes,
5492  IN EFI_STATUS Status,
5493  IN CONST CHAR8 * pQueueType,
5494  IN ESL_PACKET ** ppQueueHead,
5495  IN ESL_PACKET ** ppQueueTail,
5496  IN ESL_IO_MGMT ** ppActive,
5497  IN ESL_IO_MGMT ** ppFree
5498  )
5499{
5500  ESL_PACKET * pCurrentPacket;
5501  ESL_IO_MGMT * pIoNext;
5502  ESL_PACKET * pNextPacket;
5503  ESL_PACKET * pPacket;
5504  ESL_PORT * pPort;
5505  ESL_SOCKET * pSocket;
5506
5507  DBG_ENTER ( );
5508  VERIFY_AT_TPL ( TPL_SOCKETS );
5509
5510  //
5511  //  Locate the active transmit packet
5512  //
5513  pPacket = pIo->pPacket;
5514  pPort = pIo->pPort;
5515  pSocket = pPort->pSocket;
5516
5517  //
5518  //  No more packet
5519  //
5520  pIo->pPacket = NULL;
5521
5522  //
5523  //  Remove the IO structure from the active list
5524  //
5525  pIoNext = *ppActive;
5526  while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
5527  {
5528    pIoNext = pIoNext->pNext;
5529  }
5530  ASSERT ( NULL != pIoNext );
5531  if ( pIoNext == pIo ) {
5532    *ppActive = pIo->pNext;       //  Beginning of list
5533  }
5534  else {
5535    pIoNext->pNext = pIo->pNext;  //  Middle of list
5536  }
5537
5538  //
5539  //  Free the IO structure
5540  //
5541  pIo->pNext = *ppFree;
5542  *ppFree = pIo;
5543
5544  //
5545  //  Display the results
5546  //
5547  DEBUG (( DEBUG_TX | DEBUG_INFO,
5548            "0x%08x: pIo Released\r\n",
5549            pIo ));
5550
5551  //
5552  //  Save any transmit error
5553  //
5554  if ( EFI_ERROR ( Status )) {
5555    if ( !EFI_ERROR ( pSocket->TxError )) {
5556      pSocket->TxError = Status;
5557    }
5558    DEBUG (( DEBUG_TX | DEBUG_INFO,
5559              "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5560              pQueueType,
5561              pPacket,
5562              Status ));
5563
5564    //
5565    //  Empty the normal transmit list
5566    //
5567    pCurrentPacket = pPacket;
5568    pNextPacket = *ppQueueHead;
5569    while ( NULL != pNextPacket ) {
5570      pPacket = pNextPacket;
5571      pNextPacket = pPacket->pNext;
5572      EslSocketPacketFree ( pPacket, DEBUG_TX );
5573    }
5574    *ppQueueHead = NULL;
5575    *ppQueueTail = NULL;
5576    pPacket = pCurrentPacket;
5577  }
5578  else {
5579    DEBUG (( DEBUG_TX | DEBUG_INFO,
5580              "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5581              pPacket,
5582              pQueueType,
5583              LengthInBytes ));
5584
5585    //
5586    //  Verify the transmit engine is still running
5587    //
5588    if ( !pPort->bCloseNow ) {
5589      //
5590      //  Start the next packet transmission
5591      //
5592      EslSocketTxStart ( pPort,
5593                         ppQueueHead,
5594                         ppQueueTail,
5595                         ppActive,
5596                         ppFree );
5597    }
5598  }
5599
5600  //
5601  //  Release this packet
5602  //
5603  EslSocketPacketFree ( pPacket, DEBUG_TX );
5604
5605  //
5606  //  Finish the close operation if necessary
5607  //
5608  if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
5609    //
5610    //  Indicate that the transmit is complete
5611    //
5612    EslSocketPortCloseTxDone ( pPort );
5613  }
5614
5615  DBG_EXIT ( );
5616}
5617
5618
5619/** Transmit data using a network connection.
5620
5621  This support routine starts a transmit operation on the
5622  underlying network layer.
5623
5624  The network specific code calls this routine to start a
5625  transmit operation.  See the \ref TransmitEngine section.
5626
5627  @param[in]  pPort           Address of an ::ESL_PORT structure
5628  @param[in]  ppQueueHead     Transmit queue head address
5629  @param[in]  ppQueueTail     Transmit queue tail address
5630  @param[in]  ppActive        Active transmit queue address
5631  @param[in]  ppFree          Free transmit queue address
5632**/
5633VOID
5634EslSocketTxStart (
5635  IN ESL_PORT * pPort,
5636  IN ESL_PACKET ** ppQueueHead,
5637  IN ESL_PACKET ** ppQueueTail,
5638  IN ESL_IO_MGMT ** ppActive,
5639  IN ESL_IO_MGMT ** ppFree
5640  )
5641{
5642  UINT8 * pBuffer;
5643  ESL_IO_MGMT * pIo;
5644  ESL_PACKET * pNextPacket;
5645  ESL_PACKET * pPacket;
5646  VOID ** ppTokenData;
5647  ESL_SOCKET * pSocket;
5648  EFI_STATUS Status;
5649
5650  DBG_ENTER ( );
5651
5652  //
5653  //  Assume success
5654  //
5655  Status = EFI_SUCCESS;
5656
5657  //
5658  //  Get the packet from the queue head
5659  //
5660  pPacket = *ppQueueHead;
5661  pIo = *ppFree;
5662  if (( NULL != pPacket ) && ( NULL != pIo )) {
5663    pSocket = pPort->pSocket;
5664    //
5665    //     *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5666    //          |
5667    //          V
5668    //        +------------+   +------------+   +------------+
5669    //  Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5670    //        +------------+   +------------+   +------------+
5671    //                                                     ^
5672    //                                                     |
5673    //     *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5674    //
5675    //
5676    //  Remove the packet from the queue
5677    //
5678    pNextPacket = pPacket->pNext;
5679    *ppQueueHead = pNextPacket;
5680    if ( NULL == pNextPacket ) {
5681      *ppQueueTail = NULL;
5682    }
5683    pPacket->pNext = NULL;
5684
5685    //
5686    //  Eliminate the need for IP4 and UDP4 specific routines by
5687    //  connecting the token with the TX data control structure here.
5688    //
5689    //    +--------------------+   +--------------------+
5690    //    | ESL_IO_MGMT        |   | ESL_PACKET         |
5691    //    |                    |   |                    |
5692    //    |    +---------------+   +----------------+   |
5693    //    |    | Token         |   | Buffer Length  |   |
5694    //    |    |        TxData --> | Buffer Address |   |
5695    //    |    |               |   +----------------+---+
5696    //    |    |        Event  |   | Data Buffer        |
5697    //    +----+---------------+   |                    |
5698    //                             +--------------------+
5699    //
5700    //  Compute the address of the TxData pointer in the token
5701    //
5702    pBuffer = (UINT8 *)&pIo->Token;
5703    pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
5704    ppTokenData = (VOID **)pBuffer;
5705
5706    //
5707    //  Compute the address of the TX data control structure in the packet
5708    //
5709    //      * EFI_IP4_TRANSMIT_DATA
5710    //      * EFI_TCP4_TRANSMIT_DATA
5711    //      * EFI_UDP4_TRANSMIT_DATA
5712    //
5713    pBuffer = (UINT8 *)pPacket;
5714    pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
5715
5716    //
5717    //  Connect the token to the transmit data control structure
5718    //
5719    *ppTokenData = (VOID **)pBuffer;
5720
5721    //
5722    //  Display the results
5723    //
5724    DEBUG (( DEBUG_TX | DEBUG_INFO,
5725              "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5726              pIo,
5727              pPacket ));
5728
5729    //
5730    //  Start the transmit operation
5731    //
5732    Status = pPort->pfnTxStart ( pPort->pProtocol.v,
5733                                 &pIo->Token );
5734    if ( !EFI_ERROR ( Status )) {
5735      //
5736      //  Connect the structures
5737      //
5738      pIo->pPacket = pPacket;
5739
5740      //
5741      //          +-------------+   +-------------+   +-------------+
5742      //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5743      //          +-------------+   +-------------+   +-------------+
5744      //              ^
5745      //              |
5746      //          *ppFree:  pPort->pTxFree or pTxOobFree
5747      //
5748      //
5749      //  Remove the IO structure from the queue
5750      //
5751      *ppFree = pIo->pNext;
5752
5753      //
5754      //         *ppActive:  pPort->pTxActive or pTxOobActive
5755      //             |
5756      //             V
5757      //          +-------------+   +-------------+   +-------------+
5758      //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5759      //          +-------------+   +-------------+   +-------------+
5760      //
5761      //
5762      //  Mark this packet as active
5763      //
5764      pIo->pPacket = pPacket;
5765      pIo->pNext = *ppActive;
5766      *ppActive = pIo;
5767    }
5768    else {
5769      //
5770      //  Display the transmit error
5771      //
5772      DEBUG (( DEBUG_TX | DEBUG_INFO,
5773                "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
5774                pIo,
5775                pPacket,
5776                Status ));
5777      if ( EFI_SUCCESS == pSocket->TxError ) {
5778        pSocket->TxError = Status;
5779      }
5780
5781      //
5782      //  Free the IO structure
5783      //
5784      pIo->pNext = *ppFree;
5785      *ppFree = pIo;
5786
5787      //
5788      //  Discard the transmit buffer
5789      //
5790      EslSocketPacketFree ( pPacket, DEBUG_TX );
5791    }
5792  }
5793
5794  DBG_EXIT ( );
5795}
5796