• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 **/
466 CONST 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 
509 CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
510 
511 /// APIs to support the various socket types for the v4 network stack.
512 CONST 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.
522 CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
523 
524 
525 /// APIs to support the various socket types for the v6 network stack.
526 CONST 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.
536 CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
537 
538 
539 /// Global management structure for the socket layer.
540 ESL_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  **/
564 EFI_STATUS
EslSocket(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int domain,IN int type,IN int protocol,IN int * pErrno)565 EslSocket (
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  **/
728 EFI_STATUS
EslSocketAccept(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN struct sockaddr * pSockAddr,IN OUT socklen_t * pSockAddrLength,IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,IN int * pErrno)729 EslSocketAccept (
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 **/
924 EFI_STATUS
925 EFIAPI
EslSocketAllocate(IN OUT EFI_HANDLE * pChildHandle,IN UINTN DebugFlags,IN OUT ESL_SOCKET ** ppSocket)926 EslSocketAllocate (
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 **/
1065 EFI_STATUS
EslSocketBind(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN CONST struct sockaddr * pSockAddr,IN socklen_t SockAddrLength,OUT int * pErrno)1066 EslSocketBind (
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 **/
1255 EFI_STATUS
EslSocketBindTest(IN ESL_PORT * pPort,IN int ErrnoValue)1256 EslSocketBindTest (
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 **/
1337 EFI_STATUS
EslSocketClosePoll(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int * pErrno)1338 EslSocketClosePoll (
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 **/
1479 EFI_STATUS
EslSocketCloseStart(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN BOOLEAN bCloseNow,IN int * pErrno)1480 EslSocketCloseStart (
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  **/
1588 EFI_STATUS
EslSocketConnect(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN const struct sockaddr * pSockAddr,IN socklen_t SockAddrLength,IN int * pErrno)1589 EslSocketConnect (
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 **/
1817 UINT8 *
EslSocketCopyFragmentedBuffer(IN UINT32 FragmentCount,IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,IN size_t BufferLength,IN UINT8 * pBuffer,OUT size_t * pDataLength)1818 EslSocketCopyFragmentedBuffer (
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 **/
1891 EFI_STATUS
EslSocketFree(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int * pErrno)1892 EslSocketFree (
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  **/
2052 EFI_STATUS
EslSocketGetLocalAddress(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,OUT struct sockaddr * pAddress,IN OUT socklen_t * pAddressLength,IN int * pErrno)2053 EslSocketGetLocalAddress (
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  **/
2185 EFI_STATUS
EslSocketGetPeerAddress(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,OUT struct sockaddr * pAddress,IN OUT socklen_t * pAddressLength,IN int * pErrno)2186 EslSocketGetPeerAddress (
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 **/
2319 EFI_STATUS
EslSocketIoFree(IN ESL_PORT * pPort,IN ESL_IO_MGMT ** ppFreeQueue,IN UINTN DebugFlags,IN CHAR8 * pEventName)2320 EslSocketIoFree (
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 **/
2400 EFI_STATUS
EslSocketIoInit(IN ESL_PORT * pPort,IN ESL_IO_MGMT ** ppIo,IN UINTN TokenCount,IN ESL_IO_MGMT ** ppFreeQueue,IN UINTN DebugFlags,IN CHAR8 * pEventName,IN PFN_API_IO_COMPLETE pfnCompletion)2401 EslSocketIoInit (
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 **/
2503 EFI_STATUS
EslSocketIsConfigured(IN ESL_SOCKET * pSocket)2504 EslSocketIsConfigured (
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 **/
2586 EFI_STATUS
EslSocketListen(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN INT32 Backlog,OUT int * pErrno)2587 EslSocketListen (
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  **/
2750 EFI_STATUS
EslSocketOptionGet(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int level,IN int OptionName,OUT void * __restrict pOptionValue,IN OUT socklen_t * __restrict pOptionLength,IN int * pErrno)2751 EslSocketOptionGet (
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 **/
2969 EFI_STATUS
EslSocketOptionSet(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int level,IN int OptionName,IN CONST void * pOptionValue,IN socklen_t OptionLength,IN int * pErrno)2970 EslSocketOptionSet (
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 **/
3179 EFI_STATUS
EslSocketPacketAllocate(IN ESL_PACKET ** ppPacket,IN size_t LengthInBytes,IN size_t ZeroBytes,IN UINTN DebugFlags)3180 EslSocketPacketAllocate (
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 **/
3243 EFI_STATUS
EslSocketPacketFree(IN ESL_PACKET * pPacket,IN UINTN DebugFlags)3244 EslSocketPacketFree (
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 **/
3297 EFI_STATUS
EslSocketPoll(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN short Events,IN short * pEvents,IN int * pErrno)3298 EslSocketPoll (
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 **/
3489 EFI_STATUS
EslSocketPortAllocate(IN ESL_SOCKET * pSocket,IN ESL_SERVICE * pService,IN EFI_HANDLE ChildHandle,IN CONST struct sockaddr * pSockAddr,IN BOOLEAN bBindTest,IN UINTN DebugFlags,OUT ESL_PORT ** ppPort)3490 EslSocketPortAllocate (
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 **/
3739 EFI_STATUS
EslSocketPortClose(IN ESL_PORT * pPort)3740 EslSocketPortClose (
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 **/
3979 VOID
EslSocketPortCloseComplete(IN EFI_EVENT Event,IN ESL_PORT * pPort)3980 EslSocketPortCloseComplete (
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 **/
4035 EFI_STATUS
EslSocketPortCloseRxDone(IN ESL_PORT * pPort)4036 EslSocketPortCloseRxDone (
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 **/
4121 EFI_STATUS
EslSocketPortCloseStart(IN ESL_PORT * pPort,IN BOOLEAN bCloseNow,IN UINTN DebugFlags)4122 EslSocketPortCloseStart (
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 **/
4188 EFI_STATUS
EslSocketPortCloseTxDone(IN ESL_PORT * pPort)4189 EslSocketPortCloseTxDone (
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 **/
4344 EFI_STATUS
EslSocketReceive(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN INT32 Flags,IN size_t BufferLength,IN UINT8 * pBuffer,OUT size_t * pDataLength,OUT struct sockaddr * pAddress,IN OUT socklen_t * pAddressLength,IN int * pErrno)4345 EslSocketReceive (
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 **/
4694 VOID
EslSocketRxCancel(IN ESL_PORT * pPort,IN ESL_IO_MGMT * pIo)4695 EslSocketRxCancel (
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 **/
4745 VOID
EslSocketRxComplete(IN ESL_IO_MGMT * pIo,IN EFI_STATUS Status,IN UINTN LengthInBytes,IN BOOLEAN bUrgent)4746 EslSocketRxComplete (
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  **/
4952 VOID
EslSocketRxPoll(IN ESL_SOCKET * pSocket)4953 EslSocketRxPoll (
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 **/
5002 VOID
EslSocketRxStart(IN ESL_PORT * pPort)5003 EslSocketRxStart (
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 **/
5177 EFI_STATUS
EslSocketShutdown(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int How,IN int * pErrno)5178 EslSocketShutdown (
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 **/
5317 EFI_STATUS
EslSocketTransmit(IN EFI_SOCKET_PROTOCOL * pSocketProtocol,IN int Flags,IN size_t BufferLength,IN CONST UINT8 * pBuffer,OUT size_t * pDataLength,IN const struct sockaddr * pAddress,IN socklen_t AddressLength,IN int * pErrno)5318 EslSocketTransmit (
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 **/
5488 VOID
EslSocketTxComplete(IN ESL_IO_MGMT * pIo,IN UINT32 LengthInBytes,IN EFI_STATUS Status,IN CONST CHAR8 * pQueueType,IN ESL_PACKET ** ppQueueHead,IN ESL_PACKET ** ppQueueTail,IN ESL_IO_MGMT ** ppActive,IN ESL_IO_MGMT ** ppFree)5489 EslSocketTxComplete (
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 **/
5633 VOID
EslSocketTxStart(IN ESL_PORT * pPort,IN ESL_PACKET ** ppQueueHead,IN ESL_PACKET ** ppQueueTail,IN ESL_IO_MGMT ** ppActive,IN ESL_IO_MGMT ** ppFree)5634 EslSocketTxStart (
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