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