]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Socket.c
Fix a bug about the iSCSI DHCP dependency issue.
[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 the network adapter
1795 //
1796 EslSocketRxPoll ( pSocket );
1797
1798 //
1799 // Poll for connection completion
1800 //
1801 if ( NULL == pSocket->pApi->pfnConnectPoll ) {
1802 //
1803 // Already connected
1804 //
1805 pSocket->errno = EISCONN;
1806 Status = EFI_ALREADY_STARTED;
1807 }
1808 else {
1809 Status = pSocket->pApi->pfnConnectPoll ( pSocket );
1810
1811 //
1812 // Set the next state if connected
1813 //
1814 if ( EFI_NOT_READY != Status ) {
1815 if ( !EFI_ERROR ( Status )) {
1816 pSocket->State = SOCKET_STATE_CONNECTED;
1817
1818 //
1819 // Start the receive operations
1820 //
1821 EslSocketRxStart ( pSocket->pPortList );
1822 }
1823 else {
1824 pSocket->State = SOCKET_STATE_BOUND;
1825 }
1826 }
1827 }
1828 break;
1829
1830 case SOCKET_STATE_CONNECTED:
1831 //
1832 // Already connected
1833 //
1834 pSocket->errno = EISCONN;
1835 Status = EFI_ALREADY_STARTED;
1836 break;
1837 }
1838
1839 //
1840 // Release the socket layer synchronization
1841 //
1842 RESTORE_TPL ( TplPrevious );
1843 }
1844 }
1845
1846 //
1847 // Return the operation status
1848 //
1849 if ( NULL != pErrno ) {
1850 if ( NULL != pSocket ) {
1851 *pErrno = pSocket->errno;
1852 }
1853 else {
1854 //
1855 // Bad socket protocol
1856 //
1857 DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
1858 "ERROR - pSocketProtocol invalid!\r\n" ));
1859 Status = EFI_INVALID_PARAMETER;
1860 *pErrno = ENOTSOCK;
1861 }
1862 }
1863
1864 //
1865 // Return the operation status
1866 //
1867 DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));
1868 return Status;
1869 }
1870
1871
1872 /**
1873 Copy a fragmented buffer into a destination buffer.
1874
1875 This support routine copies a fragmented buffer to the caller specified buffer.
1876
1877 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1878
1879 @param [in] FragmentCount Number of fragments in the table
1880
1881 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1882
1883 @param [in] BufferLength Length of the the buffer
1884
1885 @param [in] pBuffer Address of a buffer to receive the data.
1886
1887 @param [in] pDataLength Number of received data bytes in the buffer.
1888
1889 @return Returns the address of the next free byte in the buffer.
1890
1891 **/
1892 UINT8 *
1893 EslSocketCopyFragmentedBuffer (
1894 IN UINT32 FragmentCount,
1895 IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
1896 IN size_t BufferLength,
1897 IN UINT8 * pBuffer,
1898 OUT size_t * pDataLength
1899 )
1900 {
1901 size_t BytesToCopy;
1902 UINT32 Fragment;
1903 UINT8 * pBufferEnd;
1904 UINT8 * pData;
1905
1906 DBG_ENTER ( );
1907
1908 //
1909 // Validate the IP and UDP structures are identical
1910 //
1911 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
1912 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
1913 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
1914 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
1915
1916 //
1917 // Copy the received data
1918 //
1919 Fragment = 0;
1920 pBufferEnd = &pBuffer [ BufferLength ];
1921 while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
1922 //
1923 // Determine the amount of received data
1924 //
1925 pData = pFragmentTable[Fragment].FragmentBuffer;
1926 BytesToCopy = pFragmentTable[Fragment].FragmentLength;
1927 if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
1928 BytesToCopy = pBufferEnd - pBuffer;
1929 }
1930
1931 //
1932 // Move the data into the buffer
1933 //
1934 DEBUG (( DEBUG_RX,
1935 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1936 pData,
1937 pBuffer,
1938 BytesToCopy ));
1939 CopyMem ( pBuffer, pData, BytesToCopy );
1940 pBuffer += BytesToCopy;
1941 Fragment += 1;
1942 }
1943
1944 //
1945 // Return the data length and the buffer address
1946 //
1947 *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
1948 DBG_EXIT_HEX ( pBuffer );
1949 return pBuffer;
1950 }
1951
1952
1953 /**
1954 Free the socket.
1955
1956 This routine frees the socket structure and handle resources.
1957
1958 The ::close routine calls EslServiceFreeProtocol which then calls
1959 this routine to free the socket context structure and close the
1960 handle.
1961
1962 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1963
1964 @param [out] pErrno Address to receive the errno value upon completion.
1965
1966 @retval EFI_SUCCESS The socket resources were returned successfully.
1967
1968 **/
1969 EFI_STATUS
1970 EslSocketFree (
1971 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
1972 IN int * pErrno
1973 )
1974 {
1975 EFI_HANDLE ChildHandle;
1976 int errno;
1977 ESL_LAYER * pLayer;
1978 ESL_SOCKET * pSocket;
1979 ESL_SOCKET * pSocketPrevious;
1980 EFI_STATUS Status;
1981 EFI_TPL TplPrevious;
1982
1983 DBG_ENTER ( );
1984
1985 //
1986 // Assume failure
1987 //
1988 errno = EIO;
1989 pSocket = NULL;
1990 Status = EFI_INVALID_PARAMETER;
1991
1992 //
1993 // Validate the socket
1994 //
1995 pLayer = &mEslLayer;
1996 if ( NULL != pSocketProtocol ) {
1997 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
1998
1999 //
2000 // Synchronize with the socket layer
2001 //
2002 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2003
2004 //
2005 // Walk the socket list
2006 //
2007 pSocketPrevious = pLayer->pSocketList;
2008 if ( NULL != pSocketPrevious ) {
2009 if ( pSocket == pSocketPrevious ) {
2010 //
2011 // Remove the socket from the head of the list
2012 //
2013 pLayer->pSocketList = pSocket->pNext;
2014 }
2015 else {
2016 //
2017 // Find the socket in the middle of the list
2018 //
2019 while (( NULL != pSocketPrevious )
2020 && ( pSocket != pSocketPrevious->pNext )) {
2021 //
2022 // Set the next socket
2023 //
2024 pSocketPrevious = pSocketPrevious->pNext;
2025 }
2026 if ( NULL != pSocketPrevious ) {
2027 //
2028 // Remove the socket from the middle of the list
2029 //
2030 pSocketPrevious = pSocket->pNext;
2031 }
2032 }
2033 }
2034 else {
2035 DEBUG (( DEBUG_ERROR | DEBUG_POOL,
2036 "ERROR - Socket list is empty!\r\n" ));
2037 }
2038
2039 //
2040 // Release the socket layer synchronization
2041 //
2042 RESTORE_TPL ( TplPrevious );
2043
2044 //
2045 // Determine if the socket was found
2046 //
2047 if ( NULL != pSocketPrevious ) {
2048 pSocket->pNext = NULL;
2049
2050 //
2051 // Remove the socket protocol
2052 //
2053 ChildHandle = pSocket->SocketProtocol.SocketHandle;
2054 Status = gBS->UninstallMultipleProtocolInterfaces (
2055 ChildHandle,
2056 &gEfiSocketProtocolGuid,
2057 &pSocket->SocketProtocol,
2058 NULL );
2059 if ( !EFI_ERROR ( Status )) {
2060 DEBUG (( DEBUG_POOL | DEBUG_INFO,
2061 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
2062 ChildHandle ));
2063
2064 //
2065 // Free the socket structure
2066 //
2067 Status = gBS->FreePool ( pSocket );
2068 if ( !EFI_ERROR ( Status )) {
2069 DEBUG (( DEBUG_POOL,
2070 "0x%08x: Free pSocket, %d bytes\r\n",
2071 pSocket,
2072 sizeof ( *pSocket )));
2073 errno = 0;
2074 }
2075 else {
2076 DEBUG (( DEBUG_ERROR | DEBUG_POOL,
2077 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2078 pSocket,
2079 Status ));
2080 }
2081 }
2082 else {
2083 DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
2084 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2085 ChildHandle,
2086 Status ));
2087 }
2088 }
2089 else {
2090 DEBUG (( DEBUG_ERROR | DEBUG_INFO,
2091 "ERROR - The socket was not in the socket list!\r\n" ));
2092 Status = EFI_NOT_FOUND;
2093 }
2094 }
2095 else {
2096 DEBUG (( DEBUG_ERROR,
2097 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2098 }
2099
2100 //
2101 // Return the errno value if possible
2102 //
2103 if ( NULL != pErrno ) {
2104 *pErrno = errno;
2105 }
2106
2107 //
2108 // Return the operation status
2109 //
2110 DBG_EXIT_STATUS ( Status );
2111 return Status;
2112 }
2113
2114
2115 /**
2116 Get the local address.
2117
2118 This routine calls the network specific layer to get the network
2119 address of the local host connection point.
2120
2121 The ::getsockname routine calls this routine to obtain the network
2122 address associated with the local host connection point.
2123
2124 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2125
2126 @param [out] pAddress Network address to receive the local system address
2127
2128 @param [in,out] pAddressLength Length of the local network address structure
2129
2130 @param [out] pErrno Address to receive the errno value upon completion.
2131
2132 @retval EFI_SUCCESS - Local address successfully returned
2133
2134 **/
2135 EFI_STATUS
2136 EslSocketGetLocalAddress (
2137 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2138 OUT struct sockaddr * pAddress,
2139 IN OUT socklen_t * pAddressLength,
2140 IN int * pErrno
2141 )
2142 {
2143 socklen_t LengthInBytes;
2144 ESL_PORT * pPort;
2145 ESL_SOCKET * pSocket;
2146 EFI_STATUS Status;
2147 EFI_TPL TplPrevious;
2148
2149 DBG_ENTER ( );
2150
2151 //
2152 // Assume success
2153 //
2154 Status = EFI_SUCCESS;
2155
2156 //
2157 // Validate the socket
2158 //
2159 pSocket = NULL;
2160 if ( NULL != pSocketProtocol ) {
2161 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2162
2163 //
2164 // Verify the socket state
2165 //
2166 EslSocketIsConfigured ( pSocket );
2167 if ( pSocket->bAddressSet ) {
2168 //
2169 // Verify the address buffer and length address
2170 //
2171 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
2172 //
2173 // Verify the API
2174 //
2175 if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
2176 Status = EFI_UNSUPPORTED;
2177 pSocket->errno = ENOTSUP;
2178 }
2179 else {
2180 //
2181 // Synchronize with the socket layer
2182 //
2183 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2184
2185 //
2186 // Verify that there is just a single connection
2187 //
2188 pPort = pSocket->pPortList;
2189 if ( NULL != pPort ) {
2190 //
2191 // Verify the address length
2192 //
2193 LengthInBytes = pSocket->pApi->AddressLength;
2194 if (( LengthInBytes <= *pAddressLength )
2195 && ( 255 >= LengthInBytes )) {
2196 //
2197 // Return the local address and address length
2198 //
2199 ZeroMem ( pAddress, LengthInBytes );
2200 pAddress->sa_len = (uint8_t)LengthInBytes;
2201 *pAddressLength = pAddress->sa_len;
2202 pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
2203 pSocket->errno = 0;
2204 Status = EFI_SUCCESS;
2205 }
2206 else {
2207 pSocket->errno = EINVAL;
2208 Status = EFI_INVALID_PARAMETER;
2209 }
2210 }
2211 else {
2212 pSocket->errno = ENOTCONN;
2213 Status = EFI_NOT_STARTED;
2214 }
2215
2216 //
2217 // Release the socket layer synchronization
2218 //
2219 RESTORE_TPL ( TplPrevious );
2220 }
2221 }
2222 else {
2223 pSocket->errno = EINVAL;
2224 Status = EFI_INVALID_PARAMETER;
2225 }
2226 }
2227 else {
2228 //
2229 // Address not set
2230 //
2231 Status = EFI_NOT_STARTED;
2232 pSocket->errno = EADDRNOTAVAIL;
2233 }
2234 }
2235
2236 //
2237 // Return the operation status
2238 //
2239 if ( NULL != pErrno ) {
2240 if ( NULL != pSocket ) {
2241 *pErrno = pSocket->errno;
2242 }
2243 else {
2244 Status = EFI_INVALID_PARAMETER;
2245 *pErrno = ENOTSOCK;
2246 }
2247 }
2248 DBG_EXIT_STATUS ( Status );
2249 return Status;
2250 }
2251
2252
2253 /**
2254 Get the peer address.
2255
2256 This routine calls the network specific layer to get the remote
2257 system connection point.
2258
2259 The ::getpeername routine calls this routine to obtain the network
2260 address of the remote connection point.
2261
2262 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2263
2264 @param [out] pAddress Network address to receive the remote system address
2265
2266 @param [in,out] pAddressLength Length of the remote network address structure
2267
2268 @param [out] pErrno Address to receive the errno value upon completion.
2269
2270 @retval EFI_SUCCESS - Remote address successfully returned
2271
2272 **/
2273 EFI_STATUS
2274 EslSocketGetPeerAddress (
2275 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2276 OUT struct sockaddr * pAddress,
2277 IN OUT socklen_t * pAddressLength,
2278 IN int * pErrno
2279 )
2280 {
2281 socklen_t LengthInBytes;
2282 ESL_PORT * pPort;
2283 ESL_SOCKET * pSocket;
2284 EFI_STATUS Status;
2285 EFI_TPL TplPrevious;
2286
2287 DBG_ENTER ( );
2288
2289 //
2290 // Assume success
2291 //
2292 Status = EFI_SUCCESS;
2293
2294 //
2295 // Validate the socket
2296 //
2297 pSocket = NULL;
2298 if ( NULL != pSocketProtocol ) {
2299 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2300
2301 //
2302 // Verify the socket state
2303 //
2304 Status = EslSocketIsConfigured ( pSocket );
2305 if ( !EFI_ERROR ( Status )) {
2306 //
2307 // Verify the API
2308 //
2309 if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
2310 Status = EFI_UNSUPPORTED;
2311 pSocket->errno = ENOTSUP;
2312 }
2313 else {
2314 //
2315 // Verify the address buffer and length address
2316 //
2317 if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
2318 //
2319 // Verify the socket state
2320 //
2321 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
2322 //
2323 // Synchronize with the socket layer
2324 //
2325 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2326
2327 //
2328 // Verify that there is just a single connection
2329 //
2330 pPort = pSocket->pPortList;
2331 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
2332 //
2333 // Verify the address length
2334 //
2335 LengthInBytes = pSocket->pApi->AddressLength;
2336 if ( LengthInBytes <= *pAddressLength ) {
2337 //
2338 // Return the local address
2339 //
2340 ZeroMem ( pAddress, LengthInBytes );
2341 pAddress->sa_len = (uint8_t)LengthInBytes;
2342 *pAddressLength = pAddress->sa_len;
2343 pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
2344 pSocket->errno = 0;
2345 Status = EFI_SUCCESS;
2346 }
2347 else {
2348 pSocket->errno = EINVAL;
2349 Status = EFI_INVALID_PARAMETER;
2350 }
2351 }
2352 else {
2353 pSocket->errno = ENOTCONN;
2354 Status = EFI_NOT_STARTED;
2355 }
2356
2357 //
2358 // Release the socket layer synchronization
2359 //
2360 RESTORE_TPL ( TplPrevious );
2361 }
2362 else {
2363 pSocket->errno = ENOTCONN;
2364 Status = EFI_NOT_STARTED;
2365 }
2366 }
2367 else {
2368 pSocket->errno = EINVAL;
2369 Status = EFI_INVALID_PARAMETER;
2370 }
2371 }
2372 }
2373 }
2374
2375 //
2376 // Return the operation status
2377 //
2378 if ( NULL != pErrno ) {
2379 if ( NULL != pSocket ) {
2380 *pErrno = pSocket->errno;
2381 }
2382 else {
2383 Status = EFI_INVALID_PARAMETER;
2384 *pErrno = ENOTSOCK;
2385 }
2386 }
2387 DBG_EXIT_STATUS ( Status );
2388 return Status;
2389 }
2390
2391
2392 /**
2393 Free the ESL_IO_MGMT event and structure
2394
2395 This support routine walks the free list to close the event in
2396 the ESL_IO_MGMT structure and remove the structure from the free
2397 list.
2398
2399 See the \ref TransmitEngine section.
2400
2401 @param [in] pPort Address of an ::ESL_PORT structure
2402 @param [in] ppFreeQueue Address of the free queue head
2403 @param [in] DebugFlags Flags for debug messages
2404 @param [in] pEventName Zero terminated string containing the event name
2405
2406 @retval EFI_SUCCESS - The structures were properly initialized
2407
2408 **/
2409 EFI_STATUS
2410 EslSocketIoFree (
2411 IN ESL_PORT * pPort,
2412 IN ESL_IO_MGMT ** ppFreeQueue,
2413 IN UINTN DebugFlags,
2414 IN CHAR8 * pEventName
2415 )
2416 {
2417 UINT8 * pBuffer;
2418 EFI_EVENT * pEvent;
2419 ESL_IO_MGMT * pIo;
2420 ESL_SOCKET * pSocket;
2421 EFI_STATUS Status;
2422
2423 DBG_ENTER ( );
2424
2425 //
2426 // Assume success
2427 //
2428 Status = EFI_SUCCESS;
2429
2430 //
2431 // Walk the list of IO structures
2432 //
2433 pSocket = pPort->pSocket;
2434 while ( *ppFreeQueue ) {
2435 //
2436 // Free the event for this structure
2437 //
2438 pIo = *ppFreeQueue;
2439 pBuffer = (UINT8 *)pIo;
2440 pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
2441 pEvent = (EFI_EVENT *)pBuffer;
2442 Status = gBS->CloseEvent ( *pEvent );
2443 if ( EFI_ERROR ( Status )) {
2444 DEBUG (( DEBUG_ERROR | DebugFlags,
2445 "ERROR - Failed to close the %a event, Status: %r\r\n",
2446 pEventName,
2447 Status ));
2448 pSocket->errno = ENOMEM;
2449 break;
2450 }
2451 DEBUG (( DebugFlags,
2452 "0x%08x: Closed %a event 0x%08x\r\n",
2453 pIo,
2454 pEventName,
2455 *pEvent ));
2456
2457 //
2458 // Remove this structure from the queue
2459 //
2460 *ppFreeQueue = pIo->pNext;
2461 }
2462
2463 //
2464 // Return the operation status
2465 //
2466 DBG_EXIT_STATUS ( Status );
2467 return Status;
2468 }
2469
2470
2471 /**
2472 Initialize the ESL_IO_MGMT structures
2473
2474 This support routine initializes the ESL_IO_MGMT structure and
2475 places them on to a free list.
2476
2477 This routine is called by ::EslSocketPortAllocate routines to prepare
2478 the transmit engines. See the \ref TransmitEngine section.
2479
2480 @param [in] pPort Address of an ::ESL_PORT structure
2481 @param [in, out] ppIo Address containing the first structure address. Upon
2482 return this buffer contains the next structure address.
2483 @param [in] TokenCount Number of structures to initialize
2484 @param [in] ppFreeQueue Address of the free queue head
2485 @param [in] DebugFlags Flags for debug messages
2486 @param [in] pEventName Zero terminated string containing the event name
2487 @param [in] pfnCompletion Completion routine address
2488
2489 @retval EFI_SUCCESS - The structures were properly initialized
2490
2491 **/
2492 EFI_STATUS
2493 EslSocketIoInit (
2494 IN ESL_PORT * pPort,
2495 IN ESL_IO_MGMT ** ppIo,
2496 IN UINTN TokenCount,
2497 IN ESL_IO_MGMT ** ppFreeQueue,
2498 IN UINTN DebugFlags,
2499 IN CHAR8 * pEventName,
2500 IN PFN_API_IO_COMPLETE pfnCompletion
2501 )
2502 {
2503 ESL_IO_MGMT * pEnd;
2504 EFI_EVENT * pEvent;
2505 ESL_IO_MGMT * pIo;
2506 ESL_SOCKET * pSocket;
2507 EFI_STATUS Status;
2508
2509 DBG_ENTER ( );
2510
2511 //
2512 // Assume success
2513 //
2514 Status = EFI_SUCCESS;
2515
2516 //
2517 // Walk the list of IO structures
2518 //
2519 pSocket = pPort->pSocket;
2520 pIo = *ppIo;
2521 pEnd = &pIo [ TokenCount ];
2522 while ( pEnd > pIo ) {
2523 //
2524 // Initialize the IO structure
2525 //
2526 pIo->pPort = pPort;
2527 pIo->pPacket = NULL;
2528
2529 //
2530 // Allocate the event for this structure
2531 //
2532 pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
2533 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
2534 TPL_SOCKETS,
2535 (EFI_EVENT_NOTIFY)pfnCompletion,
2536 pIo,
2537 pEvent );
2538 if ( EFI_ERROR ( Status )) {
2539 DEBUG (( DEBUG_ERROR | DebugFlags,
2540 "ERROR - Failed to create the %a event, Status: %r\r\n",
2541 pEventName,
2542 Status ));
2543 pSocket->errno = ENOMEM;
2544 break;
2545 }
2546 DEBUG (( DebugFlags,
2547 "0x%08x: Created %a event 0x%08x\r\n",
2548 pIo,
2549 pEventName,
2550 *pEvent ));
2551
2552 //
2553 // Add this structure to the queue
2554 //
2555 pIo->pNext = *ppFreeQueue;
2556 *ppFreeQueue = pIo;
2557
2558 //
2559 // Set the next structure
2560 //
2561 pIo += 1;
2562 }
2563
2564 //
2565 // Save the next structure
2566 //
2567 *ppIo = pIo;
2568
2569 //
2570 // Return the operation status
2571 //
2572 DBG_EXIT_STATUS ( Status );
2573 return Status;
2574 }
2575
2576
2577 /**
2578 Determine if the socket is configured
2579
2580 This support routine is called to determine if the socket if the
2581 configuration call was made to the network layer. The following
2582 routines call this routine to verify that they may be successful
2583 in their operations:
2584 <ul>
2585 <li>::EslSocketGetLocalAddress</li>
2586 <li>::EslSocketGetPeerAddress</li>
2587 <li>::EslSocketPoll</li>
2588 <li>::EslSocketReceive</li>
2589 <li>::EslSocketTransmit</li>
2590 </ul>
2591
2592 @param [in] pSocket Address of an ::ESL_SOCKET structure
2593
2594 @retval EFI_SUCCESS - The socket is configured
2595
2596 **/
2597 EFI_STATUS
2598 EslSocketIsConfigured (
2599 IN ESL_SOCKET * pSocket
2600 )
2601 {
2602 EFI_STATUS Status;
2603 EFI_TPL TplPrevious;
2604
2605 //
2606 // Assume success
2607 //
2608 Status = EFI_SUCCESS;
2609
2610 //
2611 // Verify the socket state
2612 //
2613 if ( !pSocket->bConfigured ) {
2614 DBG_ENTER ( );
2615
2616 //
2617 // Verify the API
2618 //
2619 if ( NULL == pSocket->pApi->pfnIsConfigured ) {
2620 Status = EFI_UNSUPPORTED;
2621 pSocket->errno = ENOTSUP;
2622 }
2623 else {
2624 //
2625 // Synchronize with the socket layer
2626 //
2627 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2628
2629 //
2630 // Determine if the socket is configured
2631 //
2632 Status = pSocket->pApi->pfnIsConfigured ( pSocket );
2633
2634 //
2635 // Release the socket layer synchronization
2636 //
2637 RESTORE_TPL ( TplPrevious );
2638
2639 //
2640 // Set errno if a failure occurs
2641 //
2642 if ( EFI_ERROR ( Status )) {
2643 pSocket->errno = EADDRNOTAVAIL;
2644 }
2645 }
2646
2647 DBG_EXIT_STATUS ( Status );
2648 }
2649
2650 //
2651 // Return the configuration status
2652 //
2653 return Status;
2654 }
2655
2656
2657 /**
2658 Establish the known port to listen for network connections.
2659
2660 This routine calls into the network protocol layer to establish
2661 a handler that is called upon connection completion. The handler
2662 is responsible for inserting the connection into the FIFO.
2663
2664 The ::listen routine indirectly calls this routine to place the
2665 socket into a state that enables connection attempts. Connections
2666 are placed in a FIFO that is serviced by the application. The
2667 application calls the ::accept (::EslSocketAccept) routine to
2668 remove the next connection from the FIFO and get the associated
2669 socket and address.
2670
2671 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2672
2673 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2674 the connections waiting for the application
2675 to call accept. Connection attempts received
2676 while the queue is full are refused.
2677
2678 @param [out] pErrno Address to receive the errno value upon completion.
2679
2680 @retval EFI_SUCCESS - Socket successfully created
2681 @retval Other - Failed to enable the socket for listen
2682
2683 **/
2684 EFI_STATUS
2685 EslSocketListen (
2686 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2687 IN INT32 Backlog,
2688 OUT int * pErrno
2689 )
2690 {
2691 ESL_SOCKET * pSocket;
2692 EFI_STATUS Status;
2693 EFI_STATUS TempStatus;
2694 EFI_TPL TplPrevious;
2695
2696 DBG_ENTER ( );
2697
2698 //
2699 // Assume success
2700 //
2701 Status = EFI_SUCCESS;
2702
2703 //
2704 // Validate the socket
2705 //
2706 pSocket = NULL;
2707 if ( NULL != pSocketProtocol ) {
2708 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2709
2710 //
2711 // Verify the API
2712 //
2713 if ( NULL == pSocket->pApi->pfnListen ) {
2714 Status = EFI_UNSUPPORTED;
2715 pSocket->errno = ENOTSUP;
2716 }
2717 else {
2718 //
2719 // Assume success
2720 //
2721 pSocket->Status = EFI_SUCCESS;
2722 pSocket->errno = 0;
2723
2724 //
2725 // Verify that the bind operation was successful
2726 //
2727 if ( SOCKET_STATE_BOUND == pSocket->State ) {
2728 //
2729 // Synchronize with the socket layer
2730 //
2731 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2732
2733 //
2734 // Create the event for SocketAccept completion
2735 //
2736 Status = gBS->CreateEvent ( 0,
2737 TPL_SOCKETS,
2738 NULL,
2739 NULL,
2740 &pSocket->WaitAccept );
2741 if ( !EFI_ERROR ( Status )) {
2742 DEBUG (( DEBUG_POOL,
2743 "0x%08x: Created WaitAccept event\r\n",
2744 pSocket->WaitAccept ));
2745 //
2746 // Set the maximum FIFO depth
2747 //
2748 if ( 0 >= Backlog ) {
2749 Backlog = MAX_PENDING_CONNECTIONS;
2750 }
2751 else {
2752 if ( SOMAXCONN < Backlog ) {
2753 Backlog = SOMAXCONN;
2754 }
2755 else {
2756 pSocket->MaxFifoDepth = Backlog;
2757 }
2758 }
2759
2760 //
2761 // Initiate the connection attempt listen
2762 //
2763 Status = pSocket->pApi->pfnListen ( pSocket );
2764
2765 //
2766 // Place the socket in the listen state if successful
2767 //
2768 if ( !EFI_ERROR ( Status )) {
2769 pSocket->State = SOCKET_STATE_LISTENING;
2770 pSocket->bListenCalled = TRUE;
2771 }
2772 else {
2773 //
2774 // Not waiting for SocketAccept to complete
2775 //
2776 TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
2777 if ( !EFI_ERROR ( TempStatus )) {
2778 DEBUG (( DEBUG_POOL,
2779 "0x%08x: Closed WaitAccept event\r\n",
2780 pSocket->WaitAccept ));
2781 pSocket->WaitAccept = NULL;
2782 }
2783 else {
2784 DEBUG (( DEBUG_ERROR | DEBUG_POOL,
2785 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2786 TempStatus ));
2787 ASSERT ( EFI_SUCCESS == TempStatus );
2788 }
2789 }
2790 }
2791 else {
2792 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
2793 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2794 Status ));
2795 pSocket->errno = ENOMEM;
2796 }
2797
2798 //
2799 // Release the socket layer synchronization
2800 //
2801 RESTORE_TPL ( TplPrevious );
2802 }
2803 else {
2804 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
2805 "ERROR - Bind operation must be performed first!\r\n" ));
2806 pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
2807 : EINVAL;
2808 Status = EFI_NO_MAPPING;
2809 }
2810 }
2811 }
2812
2813 //
2814 // Return the operation status
2815 //
2816 if ( NULL != pErrno ) {
2817 if ( NULL != pSocket ) {
2818 *pErrno = pSocket->errno;
2819 }
2820 else {
2821 Status = EFI_INVALID_PARAMETER;
2822 *pErrno = ENOTSOCK;
2823 }
2824 }
2825 DBG_EXIT_STATUS ( Status );
2826 return Status;
2827 }
2828
2829
2830 /**
2831 Get the socket options
2832
2833 This routine handles the socket level options and passes the
2834 others to the network specific layer.
2835
2836 The ::getsockopt routine calls this routine to retrieve the
2837 socket options one at a time by name.
2838
2839 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2840 @param [in] level Option protocol level
2841 @param [in] OptionName Name of the option
2842 @param [out] pOptionValue Buffer to receive the option value
2843 @param [in,out] pOptionLength Length of the buffer in bytes,
2844 upon return length of the option value in bytes
2845 @param [out] pErrno Address to receive the errno value upon completion.
2846
2847 @retval EFI_SUCCESS - Socket data successfully received
2848
2849 **/
2850 EFI_STATUS
2851 EslSocketOptionGet (
2852 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
2853 IN int level,
2854 IN int OptionName,
2855 OUT void * __restrict pOptionValue,
2856 IN OUT socklen_t * __restrict pOptionLength,
2857 IN int * pErrno
2858 )
2859 {
2860 int errno;
2861 socklen_t LengthInBytes;
2862 socklen_t MaxBytes;
2863 CONST UINT8 * pOptionData;
2864 ESL_SOCKET * pSocket;
2865 EFI_STATUS Status;
2866
2867 DBG_ENTER ( );
2868
2869 //
2870 // Assume failure
2871 //
2872 errno = EINVAL;
2873 Status = EFI_INVALID_PARAMETER;
2874
2875 //
2876 // Validate the socket
2877 //
2878 pSocket = NULL;
2879 if ( NULL == pSocketProtocol ) {
2880 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
2881 }
2882 else if ( NULL == pOptionValue ) {
2883 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
2884 }
2885 else if ( NULL == pOptionLength ) {
2886 DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
2887 }
2888 else {
2889 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
2890 LengthInBytes = 0;
2891 MaxBytes = *pOptionLength;
2892 pOptionData = NULL;
2893 switch ( level ) {
2894 default:
2895 //
2896 // See if the protocol will handle the option
2897 //
2898 if ( NULL != pSocket->pApi->pfnOptionGet ) {
2899 if ( pSocket->pApi->DefaultProtocol == level ) {
2900 Status = pSocket->pApi->pfnOptionGet ( pSocket,
2901 OptionName,
2902 (CONST void ** __restrict)&pOptionData,
2903 &LengthInBytes );
2904 errno = pSocket->errno;
2905 break;
2906 }
2907 else {
2908 //
2909 // Protocol not supported
2910 //
2911 DEBUG (( DEBUG_OPTION,
2912 "ERROR - The socket does not support this protocol!\r\n" ));
2913 }
2914 }
2915 else {
2916 //
2917 // Protocol level not supported
2918 //
2919 DEBUG (( DEBUG_OPTION,
2920 "ERROR - %a does not support any options!\r\n",
2921 pSocket->pApi->pName ));
2922 }
2923 errno = ENOPROTOOPT;
2924 Status = EFI_INVALID_PARAMETER;
2925 break;
2926
2927 case SOL_SOCKET:
2928 switch ( OptionName ) {
2929 default:
2930 //
2931 // Socket option not supported
2932 //
2933 DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
2934 errno = EINVAL;
2935 Status = EFI_INVALID_PARAMETER;
2936 break;
2937
2938 case SO_ACCEPTCONN:
2939 //
2940 // Return the listen flag
2941 //
2942 pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;
2943 LengthInBytes = sizeof ( pSocket->bListenCalled );
2944 break;
2945
2946 case SO_DEBUG:
2947 //
2948 // Return the debug flags
2949 //
2950 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
2951 LengthInBytes = sizeof ( pSocket->bOobInLine );
2952 break;
2953
2954 case SO_OOBINLINE:
2955 //
2956 // Return the out-of-band inline flag
2957 //
2958 pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
2959 LengthInBytes = sizeof ( pSocket->bOobInLine );
2960 break;
2961
2962 case SO_RCVTIMEO:
2963 //
2964 // Return the receive timeout
2965 //
2966 pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;
2967 LengthInBytes = sizeof ( pSocket->RxTimeout );
2968 break;
2969
2970 case SO_RCVBUF:
2971 //
2972 // Return the maximum receive buffer size
2973 //
2974 pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;
2975 LengthInBytes = sizeof ( pSocket->MaxRxBuf );
2976 break;
2977
2978 case SO_REUSEADDR:
2979 //
2980 // Return the address reuse flag
2981 //
2982 pOptionData = (UINT8 *)&pSocket->bReUseAddr;
2983 LengthInBytes = sizeof ( pSocket->bReUseAddr );
2984 break;
2985
2986 case SO_SNDBUF:
2987 //
2988 // Return the maximum transmit buffer size
2989 //
2990 pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;
2991 LengthInBytes = sizeof ( pSocket->MaxTxBuf );
2992 break;
2993
2994 case SO_TYPE:
2995 //
2996 // Return the socket type
2997 //
2998 pOptionData = (CONST UINT8 *)&pSocket->Type;
2999 LengthInBytes = sizeof ( pSocket->Type );
3000 break;
3001 }
3002 break;
3003 }
3004
3005 //
3006 // Return the option length
3007 //
3008 *pOptionLength = LengthInBytes;
3009
3010 //
3011 // Determine if the option is present
3012 //
3013 if ( 0 != LengthInBytes ) {
3014 //
3015 // Silently truncate the value length
3016 //
3017 if ( LengthInBytes > MaxBytes ) {
3018 DEBUG (( DEBUG_OPTION,
3019 "INFO - Truncating option from %d to %d bytes\r\n",
3020 LengthInBytes,
3021 MaxBytes ));
3022 LengthInBytes = MaxBytes;
3023 }
3024
3025 //
3026 // Return the value
3027 //
3028 CopyMem ( pOptionValue, pOptionData, LengthInBytes );
3029
3030 //
3031 // Zero fill any remaining space
3032 //
3033 if ( LengthInBytes < MaxBytes ) {
3034 ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
3035 }
3036 errno = 0;
3037 Status = EFI_SUCCESS;
3038 }
3039 }
3040
3041 //
3042 // Return the operation status
3043 //
3044 if ( NULL != pErrno ) {
3045 *pErrno = errno;
3046 }
3047 DBG_EXIT_STATUS ( Status );
3048 return Status;
3049 }
3050
3051
3052 /**
3053 Set the socket options
3054
3055 This routine handles the socket level options and passes the
3056 others to the network specific layer.
3057
3058 The ::setsockopt routine calls this routine to adjust the socket
3059 options one at a time by name.
3060
3061 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3062 @param [in] level Option protocol level
3063 @param [in] OptionName Name of the option
3064 @param [in] pOptionValue Buffer containing the option value
3065 @param [in] OptionLength Length of the buffer in bytes
3066 @param [out] pErrno Address to receive the errno value upon completion.
3067
3068 @retval EFI_SUCCESS - Option successfully set
3069
3070 **/
3071 EFI_STATUS
3072 EslSocketOptionSet (
3073 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
3074 IN int level,
3075 IN int OptionName,
3076 IN CONST void * pOptionValue,
3077 IN socklen_t OptionLength,
3078 IN int * pErrno
3079 )
3080 {
3081 BOOLEAN bTrueFalse;
3082 int errno;
3083 socklen_t LengthInBytes;
3084 UINT8 * pOptionData;
3085 ESL_SOCKET * pSocket;
3086 EFI_STATUS Status;
3087
3088 DBG_ENTER ( );
3089
3090 //
3091 // Assume failure
3092 //
3093 errno = EINVAL;
3094 Status = EFI_INVALID_PARAMETER;
3095
3096 //
3097 // Validate the socket
3098 //
3099 pSocket = NULL;
3100 if ( NULL == pSocketProtocol ) {
3101 DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
3102 }
3103 else if ( NULL == pOptionValue ) {
3104 DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
3105 }
3106 else
3107 {
3108 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
3109 if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
3110 DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
3111 }
3112 else {
3113 LengthInBytes = 0;
3114 pOptionData = NULL;
3115 switch ( level ) {
3116 default:
3117 //
3118 // See if the protocol will handle the option
3119 //
3120 if ( NULL != pSocket->pApi->pfnOptionSet ) {
3121 if ( pSocket->pApi->DefaultProtocol == level ) {
3122 Status = pSocket->pApi->pfnOptionSet ( pSocket,
3123 OptionName,
3124 pOptionValue,
3125 OptionLength );
3126 errno = pSocket->errno;
3127 break;
3128 }
3129 else {
3130 //
3131 // Protocol not supported
3132 //
3133 DEBUG (( DEBUG_OPTION,
3134 "ERROR - The socket does not support this protocol!\r\n" ));
3135 }
3136 }
3137 else {
3138 //
3139 // Protocol level not supported
3140 //
3141 DEBUG (( DEBUG_OPTION,
3142 "ERROR - %a does not support any options!\r\n",
3143 pSocket->pApi->pName ));
3144 }
3145 errno = ENOPROTOOPT;
3146 Status = EFI_INVALID_PARAMETER;
3147 break;
3148
3149 case SOL_SOCKET:
3150 switch ( OptionName ) {
3151 default:
3152 //
3153 // Option not supported
3154 //
3155 DEBUG (( DEBUG_OPTION,
3156 "ERROR - Sockets does not support this option!\r\n" ));
3157 errno = EINVAL;
3158 Status = EFI_INVALID_PARAMETER;
3159 break;
3160
3161 case SO_DEBUG:
3162 //
3163 // Set the debug flags
3164 //
3165 pOptionData = (UINT8 *)&pSocket->bOobInLine;
3166 LengthInBytes = sizeof ( pSocket->bOobInLine );
3167 break;
3168
3169 case SO_OOBINLINE:
3170 pOptionData = (UINT8 *)&pSocket->bOobInLine;
3171 LengthInBytes = sizeof ( pSocket->bOobInLine );
3172
3173 //
3174 // Validate the option length
3175 //
3176 if ( sizeof ( UINT32 ) == OptionLength ) {
3177 //
3178 // Restrict the input to TRUE or FALSE
3179 //
3180 bTrueFalse = TRUE;
3181 if ( 0 == *(UINT32 *)pOptionValue ) {
3182 bTrueFalse = FALSE;
3183 }
3184 pOptionValue = &bTrueFalse;
3185 }
3186 else {
3187 //
3188 // Force an invalid option length error
3189 //
3190 OptionLength = LengthInBytes - 1;
3191 }
3192 break;
3193
3194 case SO_RCVTIMEO:
3195 //
3196 // Return the receive timeout
3197 //
3198 pOptionData = (UINT8 *)&pSocket->RxTimeout;
3199 LengthInBytes = sizeof ( pSocket->RxTimeout );
3200 break;
3201
3202 case SO_RCVBUF:
3203 //
3204 // Return the maximum receive buffer size
3205 //
3206 pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
3207 LengthInBytes = sizeof ( pSocket->MaxRxBuf );
3208 break;
3209
3210 case SO_REUSEADDR:
3211 //
3212 // Return the address reuse flag
3213 //
3214 pOptionData = (UINT8 *)&pSocket->bReUseAddr;
3215 LengthInBytes = sizeof ( pSocket->bReUseAddr );
3216 break;
3217
3218 case SO_SNDBUF:
3219 //
3220 // Send buffer size
3221 //
3222 //
3223 // Return the maximum transmit buffer size
3224 //
3225 pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
3226 LengthInBytes = sizeof ( pSocket->MaxTxBuf );
3227 break;
3228 }
3229 break;
3230 }
3231
3232 //
3233 // Determine if an option was found
3234 //
3235 if ( 0 != LengthInBytes ) {
3236 //
3237 // Validate the option length
3238 //
3239 if ( LengthInBytes <= OptionLength ) {
3240 //
3241 // Set the option value
3242 //
3243 CopyMem ( pOptionData, pOptionValue, LengthInBytes );
3244 errno = 0;
3245 Status = EFI_SUCCESS;
3246 }
3247 else {
3248 DEBUG (( DEBUG_OPTION,
3249 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3250 OptionLength,
3251 LengthInBytes ));
3252 }
3253 }
3254 }
3255 }
3256
3257 //
3258 // Return the operation status
3259 //
3260 if ( NULL != pErrno ) {
3261 *pErrno = errno;
3262 }
3263 DBG_EXIT_STATUS ( Status );
3264 return Status;
3265 }
3266
3267
3268 /**
3269 Allocate a packet for a receive or transmit operation
3270
3271 This support routine is called by ::EslSocketRxStart and the
3272 network specific TxBuffer routines to get buffer space for the
3273 next operation.
3274
3275 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3276 @param [in] LengthInBytes Length of the packet structure
3277 @param [in] ZeroBytes Length of packet to zero
3278 @param [in] DebugFlags Flags for debug messages
3279
3280 @retval EFI_SUCCESS - The packet was allocated successfully
3281
3282 **/
3283 EFI_STATUS
3284 EslSocketPacketAllocate (
3285 IN ESL_PACKET ** ppPacket,
3286 IN size_t LengthInBytes,
3287 IN size_t ZeroBytes,
3288 IN UINTN DebugFlags
3289 )
3290 {
3291 ESL_PACKET * pPacket;
3292 EFI_STATUS Status;
3293
3294 DBG_ENTER ( );
3295
3296 //
3297 // Allocate a packet structure
3298 //
3299 LengthInBytes += sizeof ( *pPacket )
3300 - sizeof ( pPacket->Op );
3301 Status = gBS->AllocatePool ( EfiRuntimeServicesData,
3302 LengthInBytes,
3303 (VOID **)&pPacket );
3304 if ( !EFI_ERROR ( Status )) {
3305 DEBUG (( DebugFlags | DEBUG_POOL,
3306 "0x%08x: Allocate pPacket, %d bytes\r\n",
3307 pPacket,
3308 LengthInBytes ));
3309 if ( 0 != ZeroBytes ) {
3310 ZeroMem ( &pPacket->Op, ZeroBytes );
3311 }
3312 pPacket->PacketSize = LengthInBytes;
3313 }
3314 else {
3315 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
3316 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3317 LengthInBytes,
3318 Status ));
3319 pPacket = NULL;
3320 }
3321
3322 //
3323 // Return the packet
3324 //
3325 *ppPacket = pPacket;
3326
3327 //
3328 // Return the operation status
3329 //
3330 DBG_EXIT_STATUS ( Status );
3331 return Status;
3332 }
3333
3334
3335 /**
3336 Free a packet used for receive or transmit operation
3337
3338 This support routine is called by the network specific Close
3339 and TxComplete routines and during error cases in RxComplete
3340 and TxBuffer. Note that the network layers typically place
3341 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3342
3343 @param [in] pPacket Address of an ::ESL_PACKET structure
3344 @param [in] DebugFlags Flags for debug messages
3345
3346 @retval EFI_SUCCESS - The packet was allocated successfully
3347
3348 **/
3349 EFI_STATUS
3350 EslSocketPacketFree (
3351 IN ESL_PACKET * pPacket,
3352 IN UINTN DebugFlags
3353 )
3354 {
3355 UINTN LengthInBytes;
3356 EFI_STATUS Status;
3357
3358 DBG_ENTER ( );
3359
3360 //
3361 // Free a packet structure
3362 //
3363 LengthInBytes = pPacket->PacketSize;
3364 Status = gBS->FreePool ( pPacket );
3365 if ( !EFI_ERROR ( Status )) {
3366 DEBUG (( DebugFlags | DEBUG_POOL,
3367 "0x%08x: Free pPacket, %d bytes\r\n",
3368 pPacket,
3369 LengthInBytes ));
3370 }
3371 else {
3372 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
3373 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3374 pPacket,
3375 Status ));
3376 }
3377
3378 //
3379 // Return the operation status
3380 //
3381 DBG_EXIT_STATUS ( Status );
3382 return Status;
3383 }
3384
3385
3386 /**
3387 Poll a socket for pending activity.
3388
3389 This routine builds a detected event mask which is returned to
3390 the caller in the buffer provided.
3391
3392 The ::poll routine calls this routine to determine if the socket
3393 needs to be serviced as a result of connection, error, receive or
3394 transmit activity.
3395
3396 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3397
3398 @param [in] Events Events of interest for this socket
3399
3400 @param [in] pEvents Address to receive the detected events
3401
3402 @param [out] pErrno Address to receive the errno value upon completion.
3403
3404 @retval EFI_SUCCESS - Socket successfully polled
3405 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3406
3407 **/
3408 EFI_STATUS
3409 EslSocketPoll (
3410 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
3411 IN short Events,
3412 IN short * pEvents,
3413 IN int * pErrno
3414 )
3415 {
3416 short DetectedEvents;
3417 ESL_SOCKET * pSocket;
3418 EFI_STATUS Status;
3419 EFI_TPL TplPrevious;
3420 short ValidEvents;
3421
3422 DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
3423
3424 //
3425 // Assume success
3426 //
3427 Status = EFI_SUCCESS;
3428 DetectedEvents = 0;
3429 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
3430 pSocket->errno = 0;
3431
3432 //
3433 // Verify the socket state
3434 //
3435 Status = EslSocketIsConfigured ( pSocket );
3436 if ( !EFI_ERROR ( Status )) {
3437 //
3438 // Check for invalid events
3439 //
3440 ValidEvents = POLLIN
3441 | POLLPRI
3442 | POLLOUT | POLLWRNORM
3443 | POLLERR
3444 | POLLHUP
3445 | POLLNVAL
3446 | POLLRDNORM
3447 | POLLRDBAND
3448 | POLLWRBAND ;
3449 if ( 0 != ( Events & ( ~ValidEvents ))) {
3450 DetectedEvents |= POLLNVAL;
3451 DEBUG (( DEBUG_INFO | DEBUG_POLL,
3452 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3453 Events & ValidEvents,
3454 Events & ( ~ValidEvents )));
3455 }
3456 else {
3457 //
3458 // Synchronize with the socket layer
3459 //
3460 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
3461
3462 //
3463 // Increase the network performance by extending the
3464 // polling (idle) loop down into the LAN driver
3465 //
3466 EslSocketRxPoll ( pSocket );
3467
3468 //
3469 // Release the socket layer synchronization
3470 //
3471 RESTORE_TPL ( TplPrevious );
3472
3473 //
3474 // Check for pending connections
3475 //
3476 if ( 0 != pSocket->FifoDepth ) {
3477 //
3478 // A connection is waiting for an accept call
3479 // See posix connect documentation at
3480 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3481 //
3482 DetectedEvents |= POLLIN | POLLRDNORM;
3483 }
3484 if ( pSocket->bConnected ) {
3485 //
3486 // A connection is present
3487 // See posix connect documentation at
3488 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3489 //
3490 DetectedEvents |= POLLOUT | POLLWRNORM;
3491 }
3492
3493 //
3494 // The following bits are set based upon the POSIX poll documentation at
3495 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3496 //
3497
3498 //
3499 // Check for urgent receive data
3500 //
3501 if ( 0 < pSocket->RxOobBytes ) {
3502 DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;
3503 }
3504
3505 //
3506 // Check for normal receive data
3507 //
3508 if (( 0 < pSocket->RxBytes )
3509 || ( EFI_SUCCESS != pSocket->RxError )) {
3510 DetectedEvents |= POLLRDNORM | POLLIN;
3511 }
3512
3513 //
3514 // Handle the receive errors
3515 //
3516 if (( EFI_SUCCESS != pSocket->RxError )
3517 && ( 0 == ( DetectedEvents & POLLIN ))) {
3518 DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;
3519 }
3520
3521 //
3522 // Check for urgent transmit data buffer space
3523 //
3524 if (( MAX_TX_DATA > pSocket->TxOobBytes )
3525 || ( EFI_SUCCESS != pSocket->TxError )) {
3526 DetectedEvents |= POLLWRBAND;
3527 }
3528
3529 //
3530 // Check for normal transmit data buffer space
3531 //
3532 if (( MAX_TX_DATA > pSocket->TxBytes )
3533 || ( EFI_SUCCESS != pSocket->TxError )) {
3534 DetectedEvents |= POLLWRNORM;
3535 }
3536
3537 //
3538 // Handle the transmit error
3539 //
3540 if ( EFI_ERROR ( pSocket->TxError )) {
3541 DetectedEvents |= POLLERR;
3542 }
3543 }
3544 }
3545
3546 //
3547 // Return the detected events
3548 //
3549 *pEvents = DetectedEvents & ( Events
3550 | POLLERR
3551 | POLLHUP
3552 | POLLNVAL );
3553
3554 //
3555 // Return the operation status
3556 //
3557 DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));
3558 return Status;
3559 }
3560
3561
3562 /**
3563 Allocate and initialize a ESL_PORT structure.
3564
3565 This routine initializes an ::ESL_PORT structure for use by
3566 the socket. This routine calls a routine via
3567 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3568 specific resources. The resources are released later by the
3569 \ref PortCloseStateMachine.
3570
3571 This support routine is called by:
3572 <ul>
3573 <li>::EslSocketBind</li>
3574 <li>::EslTcp4ListenComplete</li>
3575 </ul>
3576 to connect the socket with the underlying network adapter
3577 to the socket.
3578
3579 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3580 @param [in] pService Address of an ::ESL_SERVICE structure.
3581 @param [in] ChildHandle Network protocol child handle
3582 @param [in] pSockAddr Address of a sockaddr structure that contains the
3583 connection point on the local machine. An IPv4 address
3584 of INADDR_ANY specifies that the connection is made to
3585 all of the network stacks on the platform. Specifying a
3586 specific IPv4 address restricts the connection to the
3587 network stack supporting that address. Specifying zero
3588 for the port causes the network layer to assign a port
3589 number from the dynamic range. Specifying a specific
3590 port number causes the network layer to use that port.
3591 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3592 @param [in] DebugFlags Flags for debug messages
3593 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3594
3595 @retval EFI_SUCCESS - Socket successfully created
3596
3597 **/
3598 EFI_STATUS
3599 EslSocketPortAllocate (
3600 IN ESL_SOCKET * pSocket,
3601 IN ESL_SERVICE * pService,
3602 IN EFI_HANDLE ChildHandle,
3603 IN CONST struct sockaddr * pSockAddr,
3604 IN BOOLEAN bBindTest,
3605 IN UINTN DebugFlags,
3606 OUT ESL_PORT ** ppPort
3607 )
3608 {
3609 UINTN LengthInBytes;
3610 UINT8 * pBuffer;
3611 ESL_IO_MGMT * pIo;
3612 ESL_LAYER * pLayer;
3613 ESL_PORT * pPort;
3614 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
3615 CONST ESL_SOCKET_BINDING * pSocketBinding;
3616 EFI_STATUS Status;
3617 EFI_STATUS TempStatus;
3618
3619 DBG_ENTER ( );
3620
3621 //
3622 // Verify the socket layer synchronization
3623 //
3624 VERIFY_TPL ( TPL_SOCKETS );
3625
3626 //
3627 // Use for/break instead of goto
3628 pSocketBinding = pService->pSocketBinding;
3629 for ( ; ; ) {
3630 //
3631 // Allocate a port structure
3632 //
3633 pLayer = &mEslLayer;
3634 LengthInBytes = sizeof ( *pPort )
3635 + ESL_STRUCTURE_ALIGNMENT_BYTES
3636 + (( pSocketBinding->RxIo
3637 + pSocketBinding->TxIoNormal
3638 + pSocketBinding->TxIoUrgent )
3639 * sizeof ( ESL_IO_MGMT ));
3640 pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
3641 if ( NULL == pPort ) {
3642 Status = EFI_OUT_OF_RESOURCES;
3643 pSocket->errno = ENOMEM;
3644 break;
3645 }
3646 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
3647 "0x%08x: Allocate pPort, %d bytes\r\n",
3648 pPort,
3649 LengthInBytes ));
3650
3651 //
3652 // Initialize the port
3653 //
3654 pPort->DebugFlags = DebugFlags;
3655 pPort->Handle = ChildHandle;
3656 pPort->pService = pService;
3657 pPort->pServiceBinding = pService->pServiceBinding;
3658 pPort->pSocket = pSocket;
3659 pPort->pSocketBinding = pService->pSocketBinding;
3660 pPort->Signature = PORT_SIGNATURE;
3661
3662 //
3663 // Open the port protocol
3664 //
3665 Status = gBS->OpenProtocol ( pPort->Handle,
3666 pSocketBinding->pNetworkProtocolGuid,
3667 &pPort->pProtocol.v,
3668 pLayer->ImageHandle,
3669 NULL,
3670 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
3671 if ( EFI_ERROR ( Status )) {
3672 DEBUG (( DEBUG_ERROR | DebugFlags,
3673 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3674 pPort->Handle ));
3675 pSocket->errno = EEXIST;
3676 break;
3677 }
3678 DEBUG (( DebugFlags,
3679 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3680 pPort->pProtocol.v,
3681 pPort->Handle ));
3682
3683 //
3684 // Initialize the port specific resources
3685 //
3686 Status = pSocket->pApi->pfnPortAllocate ( pPort,
3687 DebugFlags );
3688 if ( EFI_ERROR ( Status )) {
3689 break;
3690 }
3691
3692 //
3693 // Set the local address
3694 //
3695 Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
3696 if ( EFI_ERROR ( Status )) {
3697 break;
3698 }
3699
3700 //
3701 // Test the address/port configuration
3702 //
3703 if ( bBindTest ) {
3704 Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
3705 if ( EFI_ERROR ( Status )) {
3706 break;
3707 }
3708 }
3709
3710 //
3711 // Initialize the receive structures
3712 //
3713 pBuffer = (UINT8 *)&pPort[ 1 ];
3714 pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
3715 pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
3716 pIo = (ESL_IO_MGMT *)pBuffer;
3717 if (( 0 != pSocketBinding->RxIo )
3718 && ( NULL != pSocket->pApi->pfnRxComplete )) {
3719 Status = EslSocketIoInit ( pPort,
3720 &pIo,
3721 pSocketBinding->RxIo,
3722 &pPort->pRxFree,
3723 DebugFlags | DEBUG_POOL,
3724 "receive",
3725 pSocket->pApi->pfnRxComplete );
3726 if ( EFI_ERROR ( Status )) {
3727 break;
3728 }
3729 }
3730
3731 //
3732 // Initialize the urgent transmit structures
3733 //
3734 if (( 0 != pSocketBinding->TxIoUrgent )
3735 && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
3736 Status = EslSocketIoInit ( pPort,
3737 &pIo,
3738 pSocketBinding->TxIoUrgent,
3739 &pPort->pTxOobFree,
3740 DebugFlags | DEBUG_POOL,
3741 "urgent transmit",
3742 pSocket->pApi->pfnTxOobComplete );
3743 if ( EFI_ERROR ( Status )) {
3744 break;
3745 }
3746 }
3747
3748 //
3749 // Initialize the normal transmit structures
3750 //
3751 if (( 0 != pSocketBinding->TxIoNormal )
3752 && ( NULL != pSocket->pApi->pfnTxComplete )) {
3753 Status = EslSocketIoInit ( pPort,
3754 &pIo,
3755 pSocketBinding->TxIoNormal,
3756 &pPort->pTxFree,
3757 DebugFlags | DEBUG_POOL,
3758 "normal transmit",
3759 pSocket->pApi->pfnTxComplete );
3760 if ( EFI_ERROR ( Status )) {
3761 break;
3762 }
3763 }
3764
3765 //
3766 // Add this port to the socket
3767 //
3768 pPort->pLinkSocket = pSocket->pPortList;
3769 pSocket->pPortList = pPort;
3770 DEBUG (( DebugFlags,
3771 "0x%08x: Socket adding port: 0x%08x\r\n",
3772 pSocket,
3773 pPort ));
3774
3775 //
3776 // Add this port to the service
3777 //
3778 pPort->pLinkService = pService->pPortList;
3779 pService->pPortList = pPort;
3780
3781 //
3782 // Return the port
3783 //
3784 *ppPort = pPort;
3785 break;
3786 }
3787
3788 //
3789 // Clean up after the error if necessary
3790 //
3791 if ( EFI_ERROR ( Status )) {
3792 if ( NULL != pPort ) {
3793 //
3794 // Close the port
3795 //
3796 EslSocketPortClose ( pPort );
3797 }
3798 else {
3799 //
3800 // Close the port if necessary
3801 //
3802 pServiceBinding = pService->pServiceBinding;
3803 TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
3804 ChildHandle );
3805 if ( !EFI_ERROR ( TempStatus )) {
3806 DEBUG (( DEBUG_BIND | DEBUG_POOL,
3807 "0x%08x: %s port handle destroyed\r\n",
3808 ChildHandle,
3809 pSocketBinding->pName ));
3810 }
3811 else {
3812 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
3813 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3814 pSocketBinding->pName,
3815 ChildHandle,
3816 TempStatus ));
3817 ASSERT ( EFI_SUCCESS == TempStatus );
3818 }
3819 }
3820 }
3821 //
3822 // Return the operation status
3823 //
3824 DBG_EXIT_STATUS ( Status );
3825 return Status;
3826 }
3827
3828
3829 /**
3830 Close a port.
3831
3832 This routine releases the resources allocated by ::EslSocketPortAllocate.
3833 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3834 specific resources.
3835
3836 This routine is called by:
3837 <ul>
3838 <li>::EslSocketPortAllocate - Port initialization failure</li>
3839 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3840 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3841 </ul>
3842 See the \ref PortCloseStateMachine section.
3843
3844 @param [in] pPort Address of an ::ESL_PORT structure.
3845
3846 @retval EFI_SUCCESS The port is closed
3847 @retval other Port close error
3848
3849 **/
3850 EFI_STATUS
3851 EslSocketPortClose (
3852 IN ESL_PORT * pPort
3853 )
3854 {
3855 UINTN DebugFlags;
3856 ESL_LAYER * pLayer;
3857 ESL_PACKET * pPacket;
3858 ESL_PORT * pPreviousPort;
3859 ESL_SERVICE * pService;
3860 EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
3861 CONST ESL_SOCKET_BINDING * pSocketBinding;
3862 ESL_SOCKET * pSocket;
3863 EFI_STATUS Status;
3864
3865 DBG_ENTER ( );
3866
3867 //
3868 // Verify the socket layer synchronization
3869 //
3870 VERIFY_TPL ( TPL_SOCKETS );
3871
3872 //
3873 // Locate the port in the socket list
3874 //
3875 Status = EFI_SUCCESS;
3876 pLayer = &mEslLayer;
3877 DebugFlags = pPort->DebugFlags;
3878 pSocket = pPort->pSocket;
3879 pPreviousPort = pSocket->pPortList;
3880 if ( pPreviousPort == pPort ) {
3881 //
3882 // Remove this port from the head of the socket list
3883 //
3884 pSocket->pPortList = pPort->pLinkSocket;
3885 }
3886 else {
3887 //
3888 // Locate the port in the middle of the socket list
3889 //
3890 while (( NULL != pPreviousPort )
3891 && ( pPreviousPort->pLinkSocket != pPort )) {
3892 pPreviousPort = pPreviousPort->pLinkSocket;
3893 }
3894 if ( NULL != pPreviousPort ) {
3895 //
3896 // Remove the port from the middle of the socket list
3897 //
3898 pPreviousPort->pLinkSocket = pPort->pLinkSocket;
3899 }
3900 }
3901
3902 //
3903 // Locate the port in the service list
3904 // Note that the port may not be in the service list
3905 // if the service has been shutdown.
3906 //
3907 pService = pPort->pService;
3908 if ( NULL != pService ) {
3909 pPreviousPort = pService->pPortList;
3910 if ( pPreviousPort == pPort ) {
3911 //
3912 // Remove this port from the head of the service list
3913 //
3914 pService->pPortList = pPort->pLinkService;
3915 }
3916 else {
3917 //
3918 // Locate the port in the middle of the service list
3919 //
3920 while (( NULL != pPreviousPort )
3921 && ( pPreviousPort->pLinkService != pPort )) {
3922 pPreviousPort = pPreviousPort->pLinkService;
3923 }
3924 if ( NULL != pPreviousPort ) {
3925 //
3926 // Remove the port from the middle of the service list
3927 //
3928 pPreviousPort->pLinkService = pPort->pLinkService;
3929 }
3930 }
3931 }
3932
3933 //
3934 // Empty the urgent receive queue
3935 //
3936 while ( NULL != pSocket->pRxOobPacketListHead ) {
3937 pPacket = pSocket->pRxOobPacketListHead;
3938 pSocket->pRxOobPacketListHead = pPacket->pNext;
3939 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
3940 EslSocketPacketFree ( pPacket, DEBUG_RX );
3941 }
3942 pSocket->pRxOobPacketListTail = NULL;
3943 ASSERT ( 0 == pSocket->RxOobBytes );
3944
3945 //
3946 // Empty the receive queue
3947 //
3948 while ( NULL != pSocket->pRxPacketListHead ) {
3949 pPacket = pSocket->pRxPacketListHead;
3950 pSocket->pRxPacketListHead = pPacket->pNext;
3951 pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
3952 EslSocketPacketFree ( pPacket, DEBUG_RX );
3953 }
3954 pSocket->pRxPacketListTail = NULL;
3955 ASSERT ( 0 == pSocket->RxBytes );
3956
3957 //
3958 // Empty the receive free queue
3959 //
3960 while ( NULL != pSocket->pRxFree ) {
3961 pPacket = pSocket->pRxFree;
3962 pSocket->pRxFree = pPacket->pNext;
3963 EslSocketPacketFree ( pPacket, DEBUG_RX );
3964 }
3965
3966 //
3967 // Release the network specific resources
3968 //
3969 if ( NULL != pSocket->pApi->pfnPortClose ) {
3970 Status = pSocket->pApi->pfnPortClose ( pPort );
3971 }
3972
3973 //
3974 // Done with the normal transmit events
3975 //
3976 Status = EslSocketIoFree ( pPort,
3977 &pPort->pTxFree,
3978 DebugFlags | DEBUG_POOL,
3979 "normal transmit" );
3980
3981 //
3982 // Done with the urgent transmit events
3983 //
3984 Status = EslSocketIoFree ( pPort,
3985 &pPort->pTxOobFree,
3986 DebugFlags | DEBUG_POOL,
3987 "urgent transmit" );
3988
3989 //
3990 // Done with the receive events
3991 //
3992 Status = EslSocketIoFree ( pPort,
3993 &pPort->pRxFree,
3994 DebugFlags | DEBUG_POOL,
3995 "receive" );
3996
3997 //
3998 // Done with the lower layer network protocol
3999 //
4000 pSocketBinding = pPort->pSocketBinding;
4001 if ( NULL != pPort->pProtocol.v ) {
4002 Status = gBS->CloseProtocol ( pPort->Handle,
4003 pSocketBinding->pNetworkProtocolGuid,
4004 pLayer->ImageHandle,
4005 NULL );
4006 if ( !EFI_ERROR ( Status )) {
4007 DEBUG (( DebugFlags,
4008 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
4009 pPort->pProtocol.v,
4010 pPort->Handle ));
4011 }
4012 else {
4013 DEBUG (( DEBUG_ERROR | DebugFlags,
4014 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
4015 pPort->Handle,
4016 Status ));
4017 ASSERT ( EFI_SUCCESS == Status );
4018 }
4019 }
4020
4021 //
4022 // Done with the network port
4023 //
4024 pServiceBinding = pPort->pServiceBinding;
4025 if ( NULL != pPort->Handle ) {
4026 Status = pServiceBinding->DestroyChild ( pServiceBinding,
4027 pPort->Handle );
4028 if ( !EFI_ERROR ( Status )) {
4029 DEBUG (( DebugFlags | DEBUG_POOL,
4030 "0x%08x: %s port handle destroyed\r\n",
4031 pPort->Handle,
4032 pSocketBinding->pName ));
4033 }
4034 else {
4035 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
4036 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
4037 pSocketBinding->pName,
4038 Status ));
4039 ASSERT ( EFI_SUCCESS == Status );
4040 }
4041 }
4042
4043 //
4044 // Release the port structure
4045 //
4046 Status = gBS->FreePool ( pPort );
4047 if ( !EFI_ERROR ( Status )) {
4048 DEBUG (( DebugFlags | DEBUG_POOL,
4049 "0x%08x: Free pPort, %d bytes\r\n",
4050 pPort,
4051 sizeof ( *pPort )));
4052 }
4053 else {
4054 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
4055 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
4056 pPort,
4057 Status ));
4058 ASSERT ( EFI_SUCCESS == Status );
4059 }
4060
4061 //
4062 // Mark the socket as closed if necessary
4063 //
4064 if ( NULL == pSocket->pPortList ) {
4065 pSocket->State = SOCKET_STATE_CLOSED;
4066 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4067 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
4068 pSocket ));
4069 }
4070
4071 //
4072 // Return the operation status
4073 //
4074 DBG_EXIT_STATUS ( Status );
4075 return Status;
4076 }
4077
4078
4079 /**
4080 Port close state 3
4081
4082 This routine attempts to complete the port close operation.
4083
4084 This routine is called by the TCP layer upon completion of
4085 the close operation and by ::EslSocketPortCloseTxDone.
4086 See the \ref PortCloseStateMachine section.
4087
4088 @param [in] Event The close completion event
4089
4090 @param [in] pPort Address of an ::ESL_PORT structure.
4091
4092 **/
4093 VOID
4094 EslSocketPortCloseComplete (
4095 IN EFI_EVENT Event,
4096 IN ESL_PORT * pPort
4097 )
4098 {
4099 ESL_IO_MGMT * pIo;
4100 EFI_STATUS Status;
4101
4102 DBG_ENTER ( );
4103 VERIFY_AT_TPL ( TPL_SOCKETS );
4104
4105 //
4106 // Update the port state
4107 //
4108 pPort->State = PORT_STATE_CLOSE_DONE;
4109 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4110 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
4111 pPort ));
4112
4113 //
4114 // Shutdown the receive operation on the port
4115 //
4116 if ( NULL != pPort->pfnRxCancel ) {
4117 pIo = pPort->pRxActive;
4118 while ( NULL != pIo ) {
4119 EslSocketRxCancel ( pPort, pIo );
4120 pIo = pIo->pNext;
4121 }
4122 }
4123
4124 //
4125 // Determine if the receive operation is pending
4126 //
4127 Status = EslSocketPortCloseRxDone ( pPort );
4128 DBG_EXIT_STATUS ( Status );
4129 }
4130
4131
4132 /**
4133 Port close state 4
4134
4135 This routine determines the state of the receive operations and
4136 continues the close operation after the pending receive operations
4137 are cancelled.
4138
4139 This routine is called by
4140 <ul>
4141 <li>::EslSocketPortCloseComplete</li>
4142 <li>::EslSocketPortCloseTxDone</li>
4143 <li>::EslSocketRxComplete</li>
4144 </ul>
4145 to determine the state of the receive operations.
4146 See the \ref PortCloseStateMachine section.
4147
4148 @param [in] pPort Address of an ::ESL_PORT structure.
4149
4150 @retval EFI_SUCCESS The port is closed
4151 @retval EFI_NOT_READY The port is still closing
4152 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4153 most likely the routine was called already.
4154
4155 **/
4156 EFI_STATUS
4157 EslSocketPortCloseRxDone (
4158 IN ESL_PORT * pPort
4159 )
4160 {
4161 EFI_STATUS Status;
4162
4163 DBG_ENTER ( );
4164
4165 //
4166 // Verify the socket layer synchronization
4167 //
4168 VERIFY_TPL ( TPL_SOCKETS );
4169
4170 //
4171 // Verify that the port is closing
4172 //
4173 Status = EFI_ALREADY_STARTED;
4174 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
4175 //
4176 // Determine if the receive operation is pending
4177 //
4178 Status = EFI_NOT_READY;
4179 if ( NULL == pPort->pRxActive ) {
4180 //
4181 // The receive operation is complete
4182 // Update the port state
4183 //
4184 pPort->State = PORT_STATE_CLOSE_RX_DONE;
4185 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4186 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4187 pPort ));
4188
4189 //
4190 // Complete the port close operation
4191 //
4192 Status = EslSocketPortClose ( pPort );
4193 }
4194 else {
4195 DEBUG_CODE_BEGIN ();
4196 {
4197 ESL_IO_MGMT * pIo;
4198 //
4199 // Display the outstanding receive operations
4200 //
4201 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4202 "0x%08x: Port Close: Receive still pending!\r\n",
4203 pPort ));
4204 pIo = pPort->pRxActive;
4205 while ( NULL != pIo ) {
4206 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4207 "0x%08x: Packet pending on network adapter\r\n",
4208 pIo->pPacket ));
4209 pIo = pIo->pNext;
4210 }
4211 }
4212 DEBUG_CODE_END ( );
4213 }
4214 }
4215
4216 //
4217 // Return the operation status
4218 //
4219 DBG_EXIT_STATUS ( Status );
4220 return Status;
4221 }
4222
4223
4224 /**
4225 Start the close operation on a port, state 1.
4226
4227 This routine marks the port as closed and initiates the \ref
4228 PortCloseStateMachine. The first step is to allow the \ref
4229 TransmitEngine to run down.
4230
4231 This routine is called by ::EslSocketCloseStart to initiate the socket
4232 network specific close operation on the socket.
4233
4234 @param [in] pPort Address of an ::ESL_PORT structure.
4235 @param [in] bCloseNow Set TRUE to abort active transfers
4236 @param [in] DebugFlags Flags for debug messages
4237
4238 @retval EFI_SUCCESS The port is closed, not normally returned
4239 @retval EFI_NOT_READY The port has started the closing process
4240 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4241 most likely the routine was called already.
4242
4243 **/
4244 EFI_STATUS
4245 EslSocketPortCloseStart (
4246 IN ESL_PORT * pPort,
4247 IN BOOLEAN bCloseNow,
4248 IN UINTN DebugFlags
4249 )
4250 {
4251 ESL_SOCKET * pSocket;
4252 EFI_STATUS Status;
4253
4254 DBG_ENTER ( );
4255
4256 //
4257 // Verify the socket layer synchronization
4258 //
4259 VERIFY_TPL ( TPL_SOCKETS );
4260
4261 //
4262 // Mark the port as closing
4263 //
4264 Status = EFI_ALREADY_STARTED;
4265 pSocket = pPort->pSocket;
4266 pSocket->errno = EALREADY;
4267 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
4268
4269 //
4270 // Update the port state
4271 //
4272 pPort->State = PORT_STATE_CLOSE_STARTED;
4273 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4274 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4275 pPort ));
4276 pPort->bCloseNow = bCloseNow;
4277 pPort->DebugFlags = DebugFlags;
4278
4279 //
4280 // Determine if transmits are complete
4281 //
4282 Status = EslSocketPortCloseTxDone ( pPort );
4283 }
4284
4285 //
4286 // Return the operation status
4287 //
4288 DBG_EXIT_STATUS ( Status );
4289 return Status;
4290 }
4291
4292
4293 /**
4294 Port close state 2
4295
4296 This routine determines the state of the transmit engine and
4297 continue the close operation after the transmission is complete.
4298 The next step is to stop the \ref ReceiveEngine.
4299 See the \ref PortCloseStateMachine section.
4300
4301 This routine is called by ::EslSocketPortCloseStart to determine
4302 if the transmission is complete.
4303
4304 @param [in] pPort Address of an ::ESL_PORT structure.
4305
4306 @retval EFI_SUCCESS The port is closed, not normally returned
4307 @retval EFI_NOT_READY The port is still closing
4308 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4309 most likely the routine was called already.
4310
4311 **/
4312 EFI_STATUS
4313 EslSocketPortCloseTxDone (
4314 IN ESL_PORT * pPort
4315 )
4316 {
4317 ESL_IO_MGMT * pIo;
4318 ESL_SOCKET * pSocket;
4319 EFI_STATUS Status;
4320
4321 DBG_ENTER ( );
4322
4323 //
4324 // Verify the socket layer synchronization
4325 //
4326 VERIFY_TPL ( TPL_SOCKETS );
4327
4328 //
4329 // All transmissions are complete or must be stopped
4330 // Mark the port as TX complete
4331 //
4332 Status = EFI_ALREADY_STARTED;
4333 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
4334 //
4335 // Verify that the transmissions are complete
4336 //
4337 pSocket = pPort->pSocket;
4338 if ( pPort->bCloseNow
4339 || ( EFI_SUCCESS != pSocket->TxError )
4340 || (( NULL == pPort->pTxActive )
4341 && ( NULL == pPort->pTxOobActive ))) {
4342 //
4343 // Update the port state
4344 //
4345 pPort->State = PORT_STATE_CLOSE_TX_DONE;
4346 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4347 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4348 pPort ));
4349
4350 //
4351 // Close the port
4352 // Skip the close operation if the port is not configured
4353 //
4354 Status = EFI_SUCCESS;
4355 pSocket = pPort->pSocket;
4356 if (( pPort->bConfigured )
4357 && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
4358 //
4359 // Start the close operation
4360 //
4361 Status = pSocket->pApi->pfnPortCloseOp ( pPort );
4362 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4363 "0x%08x: Port Close: Close operation still pending!\r\n",
4364 pPort ));
4365 ASSERT ( EFI_SUCCESS == Status );
4366 }
4367 else {
4368 //
4369 // The receive operation is complete
4370 // Update the port state
4371 //
4372 EslSocketPortCloseComplete ( NULL, pPort );
4373 }
4374 }
4375 else {
4376 //
4377 // Transmissions are still active, exit
4378 //
4379 Status = EFI_NOT_READY;
4380 pSocket->errno = EAGAIN;
4381 DEBUG_CODE_BEGIN ( );
4382 {
4383 ESL_PACKET * pPacket;
4384
4385 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4386 "0x%08x: Port Close: Transmits are still pending!\r\n",
4387 pPort ));
4388
4389 //
4390 // Display the pending urgent transmit packets
4391 //
4392 pPacket = pSocket->pTxOobPacketListHead;
4393 while ( NULL != pPacket ) {
4394 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4395 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4396 pPacket,
4397 pPacket->PacketSize ));
4398 pPacket = pPacket->pNext;
4399 }
4400
4401 pIo = pPort->pTxOobActive;
4402 while ( NULL != pIo ) {
4403 pPacket = pIo->pPacket;
4404 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4405 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4406 pPacket,
4407 pPacket->PacketSize,
4408 pIo ));
4409 pIo = pIo->pNext;
4410 }
4411
4412 //
4413 // Display the pending normal transmit packets
4414 //
4415 pPacket = pSocket->pTxPacketListHead;
4416 while ( NULL != pPacket ) {
4417 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4418 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4419 pPacket,
4420 pPacket->PacketSize ));
4421 pPacket = pPacket->pNext;
4422 }
4423
4424 pIo = pPort->pTxActive;
4425 while ( NULL != pIo ) {
4426 pPacket = pIo->pPacket;
4427 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
4428 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4429 pPacket,
4430 pPacket->PacketSize,
4431 pIo ));
4432 pIo = pIo->pNext;
4433 }
4434 }
4435 DEBUG_CODE_END ();
4436 }
4437 }
4438
4439 //
4440 // Return the operation status
4441 //
4442 DBG_EXIT_STATUS ( Status );
4443 return Status;
4444 }
4445
4446
4447 /**
4448 Receive data from a network connection.
4449
4450 This routine calls the network specific routine to remove the
4451 next portion of data from the receive queue and return it to the
4452 caller.
4453
4454 The ::recvfrom routine calls this routine to determine if any data
4455 is received from the remote system. Note that the other routines
4456 ::recv and ::read are layered on top of ::recvfrom.
4457
4458 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4459
4460 @param [in] Flags Message control flags
4461
4462 @param [in] BufferLength Length of the the buffer
4463
4464 @param [in] pBuffer Address of a buffer to receive the data.
4465
4466 @param [in] pDataLength Number of received data bytes in the buffer.
4467
4468 @param [out] pAddress Network address to receive the remote system address
4469
4470 @param [in,out] pAddressLength Length of the remote network address structure
4471
4472 @param [out] pErrno Address to receive the errno value upon completion.
4473
4474 @retval EFI_SUCCESS - Socket data successfully received
4475
4476 **/
4477 EFI_STATUS
4478 EslSocketReceive (
4479 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
4480 IN INT32 Flags,
4481 IN size_t BufferLength,
4482 IN UINT8 * pBuffer,
4483 OUT size_t * pDataLength,
4484 OUT struct sockaddr * pAddress,
4485 IN OUT socklen_t * pAddressLength,
4486 IN int * pErrno
4487 )
4488 {
4489 union {
4490 struct sockaddr_in v4;
4491 struct sockaddr_in6 v6;
4492 } Addr;
4493 socklen_t AddressLength;
4494 BOOLEAN bConsumePacket;
4495 BOOLEAN bUrgentQueue;
4496 size_t DataLength;
4497 ESL_PACKET * pNextPacket;
4498 ESL_PACKET * pPacket;
4499 ESL_PORT * pPort;
4500 ESL_PACKET ** ppQueueHead;
4501 ESL_PACKET ** ppQueueTail;
4502 struct sockaddr * pRemoteAddress;
4503 size_t * pRxDataBytes;
4504 ESL_SOCKET * pSocket;
4505 size_t SkipBytes;
4506 EFI_STATUS Status;
4507 EFI_TPL TplPrevious;
4508
4509 DBG_ENTER ( );
4510
4511 //
4512 // Assume success
4513 //
4514 Status = EFI_SUCCESS;
4515
4516 //
4517 // Validate the socket
4518 //
4519 pSocket = NULL;
4520 if ( NULL != pSocketProtocol ) {
4521 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
4522
4523 //
4524 // Validate the return address parameters
4525 //
4526 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
4527 //
4528 // Return the transmit error if necessary
4529 //
4530 if ( EFI_SUCCESS != pSocket->TxError ) {
4531 pSocket->errno = EIO;
4532 Status = pSocket->TxError;
4533 pSocket->TxError = EFI_SUCCESS;
4534 }
4535 else {
4536 //
4537 // Verify the socket state
4538 //
4539 Status = EslSocketIsConfigured ( pSocket );
4540 if ( !EFI_ERROR ( Status )) {
4541 //
4542 // Validate the buffer length
4543 //
4544 if (( NULL == pDataLength )
4545 || ( NULL == pBuffer )) {
4546 if ( NULL == pDataLength ) {
4547 DEBUG (( DEBUG_RX,
4548 "ERROR - pDataLength is NULL!\r\n" ));
4549 }
4550 else {
4551 DEBUG (( DEBUG_RX,
4552 "ERROR - pBuffer is NULL!\r\n" ));
4553 }
4554 Status = EFI_INVALID_PARAMETER;
4555 pSocket->errno = EFAULT;
4556 }
4557 else {
4558 //
4559 // Verify the API
4560 //
4561 if ( NULL == pSocket->pApi->pfnReceive ) {
4562 Status = EFI_UNSUPPORTED;
4563 pSocket->errno = ENOTSUP;
4564 }
4565 else {
4566 //
4567 // Zero the receive address if being returned
4568 //
4569 pRemoteAddress = NULL;
4570 if ( NULL != pAddress ) {
4571 pRemoteAddress = (struct sockaddr *)&Addr;
4572 ZeroMem ( pRemoteAddress, sizeof ( Addr ));
4573 pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
4574 pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
4575 }
4576
4577 //
4578 // Synchronize with the socket layer
4579 //
4580 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
4581
4582 //
4583 // Assume failure
4584 //
4585 Status = EFI_UNSUPPORTED;
4586 pSocket->errno = ENOTCONN;
4587
4588 //
4589 // Verify that the socket is connected
4590 //
4591 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
4592 //
4593 // Poll the network to increase performance
4594 //
4595 EslSocketRxPoll ( pSocket );
4596
4597 //
4598 // Locate the port
4599 //
4600 pPort = pSocket->pPortList;
4601 if ( NULL != pPort ) {
4602 //
4603 // Determine the queue head
4604 //
4605 bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
4606 if ( bUrgentQueue ) {
4607 ppQueueHead = &pSocket->pRxOobPacketListHead;
4608 ppQueueTail = &pSocket->pRxOobPacketListTail;
4609 pRxDataBytes = &pSocket->RxOobBytes;
4610 }
4611 else {
4612 ppQueueHead = &pSocket->pRxPacketListHead;
4613 ppQueueTail = &pSocket->pRxPacketListTail;
4614 pRxDataBytes = &pSocket->RxBytes;
4615 }
4616
4617 //
4618 // Determine if there is any data on the queue
4619 //
4620 *pDataLength = 0;
4621 pPacket = *ppQueueHead;
4622 if ( NULL != pPacket ) {
4623 //
4624 // Copy the received data
4625 //
4626 do {
4627 //
4628 // Attempt to receive a packet
4629 //
4630 SkipBytes = 0;
4631 bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
4632 pBuffer = pSocket->pApi->pfnReceive ( pPort,
4633 pPacket,
4634 &bConsumePacket,
4635 BufferLength,
4636 pBuffer,
4637 &DataLength,
4638 (struct sockaddr *)&Addr,
4639 &SkipBytes );
4640 *pDataLength += DataLength;
4641 BufferLength -= DataLength;
4642
4643 //
4644 // Determine if the data is being read
4645 //
4646 pNextPacket = pPacket->pNext;
4647 if ( bConsumePacket ) {
4648 //
4649 // All done with this packet
4650 // Account for any discarded data
4651 //
4652 pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
4653 if ( 0 != SkipBytes ) {
4654 DEBUG (( DEBUG_RX,
4655 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4656 pPort,
4657 SkipBytes ));
4658 }
4659
4660 //
4661 // Remove this packet from the queue
4662 //
4663 *ppQueueHead = pPacket->pNext;
4664 if ( NULL == *ppQueueHead ) {
4665 *ppQueueTail = NULL;
4666 }
4667
4668 //
4669 // Move the packet to the free queue
4670 //
4671 pPacket->pNext = pSocket->pRxFree;
4672 pSocket->pRxFree = pPacket;
4673 DEBUG (( DEBUG_RX,
4674 "0x%08x: Port freeing packet 0x%08x\r\n",
4675 pPort,
4676 pPacket ));
4677
4678 //
4679 // Restart the receive operation if necessary
4680 //
4681 if (( NULL != pPort->pRxFree )
4682 && ( MAX_RX_DATA > pSocket->RxBytes )) {
4683 EslSocketRxStart ( pPort );
4684 }
4685 }
4686
4687 //
4688 // Get the next packet
4689 //
4690 pPacket = pNextPacket;
4691 } while (( SOCK_STREAM == pSocket->Type )
4692 && ( NULL != pPacket )
4693 && ( 0 < BufferLength ));
4694
4695 //
4696 // Successful operation
4697 //
4698 Status = EFI_SUCCESS;
4699 pSocket->errno = 0;
4700 }
4701 else {
4702 //
4703 // The queue is empty
4704 // Determine if it is time to return the receive error
4705 //
4706 if ( EFI_ERROR ( pSocket->RxError )
4707 && ( NULL == pSocket->pRxPacketListHead )
4708 && ( NULL == pSocket->pRxOobPacketListHead )) {
4709 Status = pSocket->RxError;
4710 pSocket->RxError = EFI_SUCCESS;
4711 switch ( Status ) {
4712 default:
4713 pSocket->errno = EIO;
4714 break;
4715
4716 case EFI_CONNECTION_FIN:
4717 //
4718 // Continue to return zero bytes received when the
4719 // peer has successfully closed the connection
4720 //
4721 pSocket->RxError = EFI_CONNECTION_FIN;
4722 *pDataLength = 0;
4723 pSocket->errno = 0;
4724 Status = EFI_SUCCESS;
4725 break;
4726
4727 case EFI_CONNECTION_REFUSED:
4728 pSocket->errno = ECONNREFUSED;
4729 break;
4730
4731 case EFI_CONNECTION_RESET:
4732 pSocket->errno = ECONNRESET;
4733 break;
4734
4735 case EFI_HOST_UNREACHABLE:
4736 pSocket->errno = EHOSTUNREACH;
4737 break;
4738
4739 case EFI_NETWORK_UNREACHABLE:
4740 pSocket->errno = ENETUNREACH;
4741 break;
4742
4743 case EFI_PORT_UNREACHABLE:
4744 pSocket->errno = EPROTONOSUPPORT;
4745 break;
4746
4747 case EFI_PROTOCOL_UNREACHABLE:
4748 pSocket->errno = ENOPROTOOPT;
4749 break;
4750 }
4751 }
4752 else {
4753 Status = EFI_NOT_READY;
4754 pSocket->errno = EAGAIN;
4755 }
4756 }
4757 }
4758 }
4759
4760 //
4761 // Release the socket layer synchronization
4762 //
4763 RESTORE_TPL ( TplPrevious );
4764
4765 if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
4766 //
4767 // Return the remote address if requested, truncate if necessary
4768 //
4769 AddressLength = pRemoteAddress->sa_len;
4770 if ( AddressLength > *pAddressLength ) {
4771 AddressLength = *pAddressLength;
4772 }
4773 DEBUG (( DEBUG_RX,
4774 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
4775 ZeroMem ( pAddress, *pAddressLength );
4776 CopyMem ( pAddress, &Addr, AddressLength );
4777
4778 //
4779 // Update the address length
4780 //
4781 *pAddressLength = pRemoteAddress->sa_len;
4782 }
4783 }
4784 }
4785 }
4786 }
4787
4788
4789 }
4790 else {
4791 //
4792 // Bad return address pointer and length
4793 //
4794 Status = EFI_INVALID_PARAMETER;
4795 pSocket->errno = EINVAL;
4796 }
4797 }
4798
4799 //
4800 // Return the operation status
4801 //
4802 if ( NULL != pErrno ) {
4803 if ( NULL != pSocket ) {
4804 *pErrno = pSocket->errno;
4805 }
4806 else {
4807 Status = EFI_INVALID_PARAMETER;
4808 *pErrno = ENOTSOCK;
4809 }
4810 }
4811 DBG_EXIT_STATUS ( Status );
4812 return Status;
4813 }
4814
4815
4816 /**
4817 Cancel the receive operations
4818
4819 This routine cancels a pending receive operation.
4820 See the \ref ReceiveEngine section.
4821
4822 This routine is called by ::EslSocketShutdown when the socket
4823 layer is being shutdown.
4824
4825 @param [in] pPort Address of an ::ESL_PORT structure
4826 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4827
4828 **/
4829 VOID
4830 EslSocketRxCancel (
4831 IN ESL_PORT * pPort,
4832 IN ESL_IO_MGMT * pIo
4833 )
4834 {
4835 EFI_STATUS Status;
4836
4837 DBG_ENTER ( );
4838
4839 //
4840 // Cancel the outstanding receive
4841 //
4842 Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
4843 &pIo->Token );
4844 if ( !EFI_ERROR ( Status )) {
4845 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
4846 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4847 pIo->pPacket,
4848 pPort ));
4849 }
4850 else {
4851 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
4852 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4853 pIo->pPacket,
4854 pPort,
4855 Status ));
4856 }
4857 DBG_EXIT ( );
4858 }
4859
4860
4861 /**
4862 Process the receive completion
4863
4864 This routine queues the data in FIFO order in either the urgent
4865 or normal data queues depending upon the type of data received.
4866 See the \ref ReceiveEngine section.
4867
4868 This routine is called when some data is received by:
4869 <ul>
4870 <li>::EslIp4RxComplete</li>
4871 <li>::EslTcp4RxComplete</li>
4872 <li>::EslUdp4RxComplete</li>
4873 </ul>
4874
4875 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4876 @param [in] Status Receive status
4877 @param [in] LengthInBytes Length of the receive data
4878 @param [in] bUrgent TRUE if urgent data is received and FALSE
4879 for normal data.
4880
4881 **/
4882 VOID
4883 EslSocketRxComplete (
4884 IN ESL_IO_MGMT * pIo,
4885 IN EFI_STATUS Status,
4886 IN UINTN LengthInBytes,
4887 IN BOOLEAN bUrgent
4888 )
4889 {
4890 BOOLEAN bUrgentQueue;
4891 ESL_IO_MGMT * pIoNext;
4892 ESL_PACKET * pPacket;
4893 ESL_PORT * pPort;
4894 ESL_PACKET * pPrevious;
4895 ESL_PACKET ** ppQueueHead;
4896 ESL_PACKET ** ppQueueTail;
4897 size_t * pRxBytes;
4898 ESL_SOCKET * pSocket;
4899
4900 DBG_ENTER ( );
4901 VERIFY_AT_TPL ( TPL_SOCKETS );
4902
4903 //
4904 // Locate the active receive packet
4905 //
4906 pPacket = pIo->pPacket;
4907 pPort = pIo->pPort;
4908 pSocket = pPort->pSocket;
4909
4910 //
4911 // pPort->pRxActive
4912 // |
4913 // V
4914 // +-------------+ +-------------+ +-------------+
4915 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4916 // +-------------+ +-------------+ +-------------+
4917 //
4918 // +-------------+ +-------------+ +-------------+
4919 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4920 // +-------------+ +-------------+ +-------------+
4921 // ^
4922 // |
4923 // pPort->pRxFree
4924 //
4925 //
4926 // Remove the IO structure from the active list
4927 // The following code searches for the entry in the list and does not
4928 // assume that the receive operations complete in the order they were
4929 // issued to the UEFI network layer.
4930 //
4931 pIoNext = pPort->pRxActive;
4932 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
4933 {
4934 pIoNext = pIoNext->pNext;
4935 }
4936 ASSERT ( NULL != pIoNext );
4937 if ( pIoNext == pIo ) {
4938 pPort->pRxActive = pIo->pNext; // Beginning of list
4939 }
4940 else {
4941 pIoNext->pNext = pIo->pNext; // Middle of list
4942 }
4943
4944 //
4945 // Free the IO structure
4946 //
4947 pIo->pNext = pPort->pRxFree;
4948 pPort->pRxFree = pIo;
4949
4950 //
4951 // pRxOobPacketListHead pRxOobPacketListTail
4952 // | |
4953 // V V
4954 // +------------+ +------------+ +------------+
4955 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4956 // +------------+ +------------+ +------------+
4957 //
4958 // +------------+ +------------+ +------------+
4959 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4960 // +------------+ +------------+ +------------+
4961 // ^ ^
4962 // | |
4963 // pRxPacketListHead pRxPacketListTail
4964 //
4965 //
4966 // Determine the queue to use
4967 //
4968 bUrgentQueue = (BOOLEAN)( bUrgent
4969 && pSocket->pApi->bOobSupported
4970 && ( !pSocket->bOobInLine ));
4971 if ( bUrgentQueue ) {
4972 ppQueueHead = &pSocket->pRxOobPacketListHead;
4973 ppQueueTail = &pSocket->pRxOobPacketListTail;
4974 pRxBytes = &pSocket->RxOobBytes;
4975 }
4976 else {
4977 ppQueueHead = &pSocket->pRxPacketListHead;
4978 ppQueueTail = &pSocket->pRxPacketListTail;
4979 pRxBytes = &pSocket->RxBytes;
4980 }
4981
4982 //
4983 // Determine if this receive was successful
4984 //
4985 if (( !EFI_ERROR ( Status ))
4986 && ( PORT_STATE_CLOSE_STARTED > pPort->State )
4987 && ( !pSocket->bRxDisable )) {
4988 //
4989 // Account for the received data
4990 //
4991 *pRxBytes += LengthInBytes;
4992
4993 //
4994 // Log the received data
4995 //
4996 DEBUG (( DEBUG_RX | DEBUG_INFO,
4997 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4998 pPacket,
4999 bUrgentQueue ? L"urgent" : L"normal",
5000 pPort,
5001 LengthInBytes,
5002 bUrgent ? L"urgent" : L"normal" ));
5003
5004 //
5005 // Add the packet to the list tail.
5006 //
5007 pPacket->pNext = NULL;
5008 pPrevious = *ppQueueTail;
5009 if ( NULL == pPrevious ) {
5010 *ppQueueHead = pPacket;
5011 }
5012 else {
5013 pPrevious->pNext = pPacket;
5014 }
5015 *ppQueueTail = pPacket;
5016
5017 //
5018 // Attempt to restart this receive operation
5019 //
5020 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
5021 EslSocketRxStart ( pPort );
5022 }
5023 else {
5024 DEBUG (( DEBUG_RX,
5025 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
5026 pPort,
5027 pSocket->RxBytes ));
5028 }
5029 }
5030 else {
5031 if ( EFI_ERROR ( Status )) {
5032 DEBUG (( DEBUG_RX | DEBUG_INFO,
5033 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
5034 pPort,
5035 pPacket,
5036 Status ));
5037 }
5038
5039 //
5040 // Account for the receive bytes and release the driver's buffer
5041 //
5042 if ( !EFI_ERROR ( Status )) {
5043 *pRxBytes += LengthInBytes;
5044 pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
5045 }
5046
5047 //
5048 // Receive error, free the packet save the error
5049 //
5050 EslSocketPacketFree ( pPacket, DEBUG_RX );
5051 if ( !EFI_ERROR ( pSocket->RxError )) {
5052 pSocket->RxError = Status;
5053 }
5054
5055 //
5056 // Update the port state
5057 //
5058 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
5059 if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
5060 EslSocketPortCloseRxDone ( pPort );
5061 }
5062 }
5063 else {
5064 if ( EFI_ERROR ( Status )) {
5065 DEBUG (( DEBUG_RX | DEBUG_INFO,
5066 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
5067 pPort,
5068 Status ));
5069 pPort->State = PORT_STATE_RX_ERROR;
5070 }
5071 }
5072 }
5073
5074 DBG_EXIT ( );
5075 }
5076
5077
5078 /**
5079 Poll a socket for pending receive activity.
5080
5081 This routine is called at elivated TPL and extends the idle
5082 loop which polls a socket down into the LAN driver layer to
5083 determine if there is any receive activity.
5084
5085 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
5086 routines call this routine when there is nothing to do.
5087
5088 @param [in] pSocket Address of an ::EFI_SOCKET structure.
5089
5090 **/
5091 VOID
5092 EslSocketRxPoll (
5093 IN ESL_SOCKET * pSocket
5094 )
5095 {
5096 ESL_PORT * pPort;
5097
5098 DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));
5099
5100 //
5101 // Increase the network performance by extending the
5102 // polling (idle) loop down into the LAN driver
5103 //
5104 pPort = pSocket->pPortList;
5105 while ( NULL != pPort ) {
5106 //
5107 // Poll the LAN adapter
5108 //
5109 pPort->pfnRxPoll ( pPort->pProtocol.v );
5110
5111 //
5112 // Locate the next LAN adapter
5113 //
5114 pPort = pPort->pLinkSocket;
5115 }
5116
5117 DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));
5118 }
5119
5120
5121 /**
5122 Start a receive operation
5123
5124 This routine posts a receive buffer to the network adapter.
5125 See the \ref ReceiveEngine section.
5126
5127 This support routine is called by:
5128 <ul>
5129 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
5130 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5131 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5132 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
5133 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
5134 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5135 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
5136 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5137 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5138 </ul>
5139
5140 @param [in] pPort Address of an ::ESL_PORT structure.
5141
5142 **/
5143 VOID
5144 EslSocketRxStart (
5145 IN ESL_PORT * pPort
5146 )
5147 {
5148 UINT8 * pBuffer;
5149 ESL_IO_MGMT * pIo;
5150 ESL_PACKET * pPacket;
5151 ESL_SOCKET * pSocket;
5152 EFI_STATUS Status;
5153
5154 DBG_ENTER ( );
5155
5156 //
5157 // Determine if a receive is already pending
5158 //
5159 Status = EFI_SUCCESS;
5160 pPacket = NULL;
5161 pSocket = pPort->pSocket;
5162 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
5163 if (( NULL != pPort->pRxFree )
5164 && ( !pSocket->bRxDisable )
5165 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
5166 //
5167 // Start all of the pending receive operations
5168 //
5169 while ( NULL != pPort->pRxFree ) {
5170 //
5171 // Determine if there are any free packets
5172 //
5173 pPacket = pSocket->pRxFree;
5174 if ( NULL != pPacket ) {
5175 //
5176 // Remove this packet from the free list
5177 //
5178 pSocket->pRxFree = pPacket->pNext;
5179 DEBUG (( DEBUG_RX,
5180 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5181 pPort,
5182 pPacket ));
5183 }
5184 else {
5185 //
5186 // Allocate a packet structure
5187 //
5188 Status = EslSocketPacketAllocate ( &pPacket,
5189 pSocket->pApi->RxPacketBytes,
5190 pSocket->pApi->RxZeroBytes,
5191 DEBUG_RX );
5192 if ( EFI_ERROR ( Status )) {
5193 pPacket = NULL;
5194 DEBUG (( DEBUG_ERROR | DEBUG_RX,
5195 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5196 pPort,
5197 Status ));
5198 break;
5199 }
5200 }
5201
5202 //
5203 // Connect the IO and packet structures
5204 //
5205 pIo = pPort->pRxFree;
5206 pIo->pPacket = pPacket;
5207
5208 //
5209 // Eliminate the need for IP4 and UDP4 specific routines by
5210 // clearing the RX data pointer here.
5211 //
5212 // No driver buffer for this packet
5213 //
5214 // +--------------------+
5215 // | ESL_IO_MGMT |
5216 // | |
5217 // | +---------------+
5218 // | | Token |
5219 // | | RxData --> NULL
5220 // +----+---------------+
5221 //
5222 pBuffer = (UINT8 *)pIo;
5223 pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
5224 *(VOID **)pBuffer = NULL;
5225
5226 //
5227 // Network specific receive packet initialization
5228 //
5229 if ( NULL != pSocket->pApi->pfnRxStart ) {
5230 pSocket->pApi->pfnRxStart ( pPort, pIo );
5231 }
5232
5233 //
5234 // Start the receive on the packet
5235 //
5236 Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
5237 if ( !EFI_ERROR ( Status )) {
5238 DEBUG (( DEBUG_RX | DEBUG_INFO,
5239 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5240 pPacket,
5241 pPort ));
5242 //
5243 // Allocate the receive control structure
5244 //
5245 pPort->pRxFree = pIo->pNext;
5246
5247 //
5248 // Mark this receive as pending
5249 //
5250 pIo->pNext = pPort->pRxActive;
5251 pPort->pRxActive = pIo;
5252
5253 }
5254 else {
5255 DEBUG (( DEBUG_RX | DEBUG_INFO,
5256 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5257 pPort,
5258 Status ));
5259 if ( !EFI_ERROR ( pSocket->RxError )) {
5260 //
5261 // Save the error status
5262 //
5263 pSocket->RxError = Status;
5264 }
5265
5266 //
5267 // Free the packet
5268 //
5269 pIo->pPacket = NULL;
5270 pPacket->pNext = pSocket->pRxFree;
5271 pSocket->pRxFree = pPacket;
5272 break;
5273 }
5274 }
5275 }
5276 else {
5277 if ( NULL == pPort->pRxFree ) {
5278 DEBUG (( DEBUG_RX | DEBUG_INFO,
5279 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5280 pPort));
5281 }
5282 if ( pSocket->bRxDisable ) {
5283 DEBUG (( DEBUG_RX | DEBUG_INFO,
5284 "0x%08x: Port, receive disabled!\r\n",
5285 pPort ));
5286 }
5287 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
5288 DEBUG (( DEBUG_RX | DEBUG_INFO,
5289 "0x%08x: Port, is closing!\r\n",
5290 pPort ));
5291 }
5292 }
5293 }
5294 else {
5295 DEBUG (( DEBUG_ERROR | DEBUG_RX,
5296 "ERROR - Previous receive error, Status: %r\r\n",
5297 pPort->pSocket->RxError ));
5298 }
5299
5300 DBG_EXIT ( );
5301 }
5302
5303
5304 /**
5305 Shutdown the socket receive and transmit operations
5306
5307 This routine sets a flag to stop future transmissions and calls
5308 the network specific layer to cancel the pending receive operation.
5309
5310 The ::shutdown routine calls this routine to stop receive and transmit
5311 operations on the socket.
5312
5313 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5314
5315 @param [in] How Which operations to stop
5316
5317 @param [out] pErrno Address to receive the errno value upon completion.
5318
5319 @retval EFI_SUCCESS - Socket operations successfully shutdown
5320
5321 **/
5322 EFI_STATUS
5323 EslSocketShutdown (
5324 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
5325 IN int How,
5326 IN int * pErrno
5327 )
5328 {
5329 ESL_IO_MGMT * pIo;
5330 ESL_PORT * pPort;
5331 ESL_SOCKET * pSocket;
5332 EFI_STATUS Status;
5333 EFI_TPL TplPrevious;
5334
5335 DBG_ENTER ( );
5336
5337 //
5338 // Assume success
5339 //
5340 Status = EFI_SUCCESS;
5341
5342 //
5343 // Validate the socket
5344 //
5345 pSocket = NULL;
5346 if ( NULL != pSocketProtocol ) {
5347 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
5348
5349 //
5350 // Verify that the socket is connected
5351 //
5352 if ( pSocket->bConnected ) {
5353 //
5354 // Validate the How value
5355 //
5356 if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {
5357 //
5358 // Synchronize with the socket layer
5359 //
5360 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
5361
5362 //
5363 // Disable the receiver if requested
5364 //
5365 if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {
5366 pSocket->bRxDisable = TRUE;
5367 }
5368
5369 //
5370 // Disable the transmitter if requested
5371 //
5372 if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {
5373 pSocket->bTxDisable = TRUE;
5374 }
5375
5376 //
5377 // Cancel the pending receive operations
5378 //
5379 if ( pSocket->bRxDisable ) {
5380 //
5381 // Walk the list of ports
5382 //
5383 pPort = pSocket->pPortList;
5384 while ( NULL != pPort ) {
5385 //
5386 // Walk the list of active receive operations
5387 //
5388 pIo = pPort->pRxActive;
5389 while ( NULL != pIo ) {
5390 EslSocketRxCancel ( pPort, pIo );
5391 }
5392
5393 //
5394 // Set the next port
5395 //
5396 pPort = pPort->pLinkSocket;
5397 }
5398 }
5399
5400 //
5401 // Release the socket layer synchronization
5402 //
5403 RESTORE_TPL ( TplPrevious );
5404 }
5405 else {
5406 //
5407 // Invalid How value
5408 //
5409 pSocket->errno = EINVAL;
5410 Status = EFI_INVALID_PARAMETER;
5411 }
5412 }
5413 else {
5414 //
5415 // The socket is not connected
5416 //
5417 pSocket->errno = ENOTCONN;
5418 Status = EFI_NOT_STARTED;
5419 }
5420 }
5421
5422 //
5423 // Return the operation status
5424 //
5425 if ( NULL != pErrno ) {
5426 if ( NULL != pSocket ) {
5427 *pErrno = pSocket->errno;
5428 }
5429 else {
5430 Status = EFI_INVALID_PARAMETER;
5431 *pErrno = ENOTSOCK;
5432 }
5433 }
5434 DBG_EXIT_STATUS ( Status );
5435 return Status;
5436 }
5437
5438
5439 /**
5440 Send data using a network connection.
5441
5442 This routine calls the network specific layer to queue the data
5443 for transmission. Eventually the buffer will reach the head of
5444 the queue and will get transmitted over the network by the
5445 \ref TransmitEngine. For datagram
5446 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5447 the data reaches the application running on the remote system.
5448
5449 The ::sendto routine calls this routine to send data to the remote
5450 system. Note that ::send and ::write are layered on top of ::sendto.
5451
5452 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5453
5454 @param [in] Flags Message control flags
5455
5456 @param [in] BufferLength Length of the the buffer
5457
5458 @param [in] pBuffer Address of a buffer containing the data to send
5459
5460 @param [in] pDataLength Address to receive the number of data bytes sent
5461
5462 @param [in] pAddress Network address of the remote system address
5463
5464 @param [in] AddressLength Length of the remote network address structure
5465
5466 @param [out] pErrno Address to receive the errno value upon completion.
5467
5468 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5469
5470 **/
5471 EFI_STATUS
5472 EslSocketTransmit (
5473 IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
5474 IN int Flags,
5475 IN size_t BufferLength,
5476 IN CONST UINT8 * pBuffer,
5477 OUT size_t * pDataLength,
5478 IN const struct sockaddr * pAddress,
5479 IN socklen_t AddressLength,
5480 IN int * pErrno
5481 )
5482 {
5483 ESL_SOCKET * pSocket;
5484 EFI_STATUS Status;
5485 EFI_TPL TplPrevious;
5486
5487 DBG_ENTER ( );
5488
5489 //
5490 // Assume success
5491 //
5492 Status = EFI_SUCCESS;
5493
5494 //
5495 // Validate the socket
5496 //
5497 pSocket = NULL;
5498 if ( NULL != pSocketProtocol ) {
5499 pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
5500
5501 //
5502 // Return the transmit error if necessary
5503 //
5504 if ( EFI_SUCCESS != pSocket->TxError ) {
5505 pSocket->errno = EIO;
5506 Status = pSocket->TxError;
5507 pSocket->TxError = EFI_SUCCESS;
5508 }
5509 else {
5510 //
5511 // Verify the socket state
5512 //
5513 Status = EslSocketIsConfigured ( pSocket );
5514 if ( !EFI_ERROR ( Status )) {
5515 //
5516 // Verify that transmit is still allowed
5517 //
5518 if ( !pSocket->bTxDisable ) {
5519 //
5520 // Validate the buffer length
5521 //
5522 if (( NULL == pDataLength )
5523 && ( 0 > pDataLength )
5524 && ( NULL == pBuffer )) {
5525 if ( NULL == pDataLength ) {
5526 DEBUG (( DEBUG_RX,
5527 "ERROR - pDataLength is NULL!\r\n" ));
5528 }
5529 else if ( NULL == pBuffer ) {
5530 DEBUG (( DEBUG_RX,
5531 "ERROR - pBuffer is NULL!\r\n" ));
5532 }
5533 else {
5534 DEBUG (( DEBUG_RX,
5535 "ERROR - Data length < 0!\r\n" ));
5536 }
5537 Status = EFI_INVALID_PARAMETER;
5538 pSocket->errno = EFAULT;
5539 }
5540 else {
5541 //
5542 // Validate the remote network address
5543 //
5544 if (( NULL != pAddress )
5545 && ( AddressLength < pAddress->sa_len )) {
5546 DEBUG (( DEBUG_TX,
5547 "ERROR - Invalid sin_len field in address\r\n" ));
5548 Status = EFI_INVALID_PARAMETER;
5549 pSocket->errno = EFAULT;
5550 }
5551 else {
5552 //
5553 // Verify the API
5554 //
5555 if ( NULL == pSocket->pApi->pfnTransmit ) {
5556 Status = EFI_UNSUPPORTED;
5557 pSocket->errno = ENOTSUP;
5558 }
5559 else {
5560 //
5561 // Synchronize with the socket layer
5562 //
5563 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
5564
5565 //
5566 // Poll the network to increase performance
5567 //
5568 EslSocketRxPoll ( pSocket );
5569
5570 //
5571 // Attempt to buffer the packet for transmission
5572 //
5573 Status = pSocket->pApi->pfnTransmit ( pSocket,
5574 Flags,
5575 BufferLength,
5576 pBuffer,
5577 pDataLength,
5578 pAddress,
5579 AddressLength );
5580
5581 //
5582 // Release the socket layer synchronization
5583 //
5584 RESTORE_TPL ( TplPrevious );
5585 }
5586 }
5587 }
5588 }
5589 else {
5590 //
5591 // The transmitter was shutdown
5592 //
5593 pSocket->errno = EPIPE;
5594 Status = EFI_NOT_STARTED;
5595 }
5596 }
5597 }
5598 }
5599
5600 //
5601 // Return the operation status
5602 //
5603 if ( NULL != pErrno ) {
5604 if ( NULL != pSocket ) {
5605 *pErrno = pSocket->errno;
5606 }
5607 else {
5608 Status = EFI_INVALID_PARAMETER;
5609 *pErrno = ENOTSOCK;
5610 }
5611 }
5612 DBG_EXIT_STATUS ( Status );
5613 return Status;
5614 }
5615
5616
5617 /**
5618 Complete the transmit operation
5619
5620 This support routine handles the transmit completion processing for
5621 the various network layers. It frees the ::ESL_IO_MGMT structure
5622 and and frees packet resources by calling ::EslSocketPacketFree.
5623 Transmit errors are logged in ESL_SOCKET::TxError.
5624 See the \ref TransmitEngine section.
5625
5626 This routine is called by:
5627 <ul>
5628 <li>::EslIp4TxComplete</li>
5629 <li>::EslTcp4TxComplete</li>
5630 <li>::EslTcp4TxOobComplete</li>
5631 <li>::EslUdp4TxComplete</li>
5632 </ul>
5633
5634 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5635 @param [in] LengthInBytes Length of the data in bytes
5636 @param [in] Status Transmit operation status
5637 @param [in] pQueueType Zero terminated string describing queue type
5638 @param [in] ppQueueHead Transmit queue head address
5639 @param [in] ppQueueTail Transmit queue tail address
5640 @param [in] ppActive Active transmit queue address
5641 @param [in] ppFree Free transmit queue address
5642
5643 **/
5644 VOID
5645 EslSocketTxComplete (
5646 IN ESL_IO_MGMT * pIo,
5647 IN UINT32 LengthInBytes,
5648 IN EFI_STATUS Status,
5649 IN CONST CHAR8 * pQueueType,
5650 IN ESL_PACKET ** ppQueueHead,
5651 IN ESL_PACKET ** ppQueueTail,
5652 IN ESL_IO_MGMT ** ppActive,
5653 IN ESL_IO_MGMT ** ppFree
5654 )
5655 {
5656 ESL_PACKET * pCurrentPacket;
5657 ESL_IO_MGMT * pIoNext;
5658 ESL_PACKET * pNextPacket;
5659 ESL_PACKET * pPacket;
5660 ESL_PORT * pPort;
5661 ESL_SOCKET * pSocket;
5662
5663 DBG_ENTER ( );
5664 VERIFY_AT_TPL ( TPL_SOCKETS );
5665
5666 //
5667 // Locate the active transmit packet
5668 //
5669 pPacket = pIo->pPacket;
5670 pPort = pIo->pPort;
5671 pSocket = pPort->pSocket;
5672
5673 //
5674 // No more packet
5675 //
5676 pIo->pPacket = NULL;
5677
5678 //
5679 // Remove the IO structure from the active list
5680 //
5681 pIoNext = *ppActive;
5682 while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
5683 {
5684 pIoNext = pIoNext->pNext;
5685 }
5686 ASSERT ( NULL != pIoNext );
5687 if ( pIoNext == pIo ) {
5688 *ppActive = pIo->pNext; // Beginning of list
5689 }
5690 else {
5691 pIoNext->pNext = pIo->pNext; // Middle of list
5692 }
5693
5694 //
5695 // Free the IO structure
5696 //
5697 pIo->pNext = *ppFree;
5698 *ppFree = pIo;
5699
5700 //
5701 // Display the results
5702 //
5703 DEBUG (( DEBUG_TX | DEBUG_INFO,
5704 "0x%08x: pIo Released\r\n",
5705 pIo ));
5706
5707 //
5708 // Save any transmit error
5709 //
5710 if ( EFI_ERROR ( Status )) {
5711 if ( !EFI_ERROR ( pSocket->TxError )) {
5712 pSocket->TxError = Status;
5713 }
5714 DEBUG (( DEBUG_TX | DEBUG_INFO,
5715 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5716 pQueueType,
5717 pPacket,
5718 Status ));
5719
5720 //
5721 // Empty the normal transmit list
5722 //
5723 pCurrentPacket = pPacket;
5724 pNextPacket = *ppQueueHead;
5725 while ( NULL != pNextPacket ) {
5726 pPacket = pNextPacket;
5727 pNextPacket = pPacket->pNext;
5728 EslSocketPacketFree ( pPacket, DEBUG_TX );
5729 }
5730 *ppQueueHead = NULL;
5731 *ppQueueTail = NULL;
5732 pPacket = pCurrentPacket;
5733 }
5734 else {
5735 DEBUG (( DEBUG_TX | DEBUG_INFO,
5736 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5737 pPacket,
5738 pQueueType,
5739 LengthInBytes ));
5740
5741 //
5742 // Verify the transmit engine is still running
5743 //
5744 if ( !pPort->bCloseNow ) {
5745 //
5746 // Start the next packet transmission
5747 //
5748 EslSocketTxStart ( pPort,
5749 ppQueueHead,
5750 ppQueueTail,
5751 ppActive,
5752 ppFree );
5753 }
5754 }
5755
5756 //
5757 // Release this packet
5758 //
5759 EslSocketPacketFree ( pPacket, DEBUG_TX );
5760
5761 //
5762 // Finish the close operation if necessary
5763 //
5764 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
5765 //
5766 // Indicate that the transmit is complete
5767 //
5768 EslSocketPortCloseTxDone ( pPort );
5769 }
5770
5771 DBG_EXIT ( );
5772 }
5773
5774
5775 /**
5776 Transmit data using a network connection.
5777
5778 This support routine starts a transmit operation on the
5779 underlying network layer.
5780
5781 The network specific code calls this routine to start a
5782 transmit operation. See the \ref TransmitEngine section.
5783
5784 @param [in] pPort Address of an ::ESL_PORT structure
5785 @param [in] ppQueueHead Transmit queue head address
5786 @param [in] ppQueueTail Transmit queue tail address
5787 @param [in] ppActive Active transmit queue address
5788 @param [in] ppFree Free transmit queue address
5789
5790 **/
5791 VOID
5792 EslSocketTxStart (
5793 IN ESL_PORT * pPort,
5794 IN ESL_PACKET ** ppQueueHead,
5795 IN ESL_PACKET ** ppQueueTail,
5796 IN ESL_IO_MGMT ** ppActive,
5797 IN ESL_IO_MGMT ** ppFree
5798 )
5799 {
5800 UINT8 * pBuffer;
5801 ESL_IO_MGMT * pIo;
5802 ESL_PACKET * pNextPacket;
5803 ESL_PACKET * pPacket;
5804 VOID ** ppTokenData;
5805 ESL_SOCKET * pSocket;
5806 EFI_STATUS Status;
5807
5808 DBG_ENTER ( );
5809
5810 //
5811 // Assume success
5812 //
5813 Status = EFI_SUCCESS;
5814
5815 //
5816 // Get the packet from the queue head
5817 //
5818 pPacket = *ppQueueHead;
5819 pIo = *ppFree;
5820 if (( NULL != pPacket ) && ( NULL != pIo )) {
5821 pSocket = pPort->pSocket;
5822 //
5823 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5824 // |
5825 // V
5826 // +------------+ +------------+ +------------+
5827 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5828 // +------------+ +------------+ +------------+
5829 // ^
5830 // |
5831 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5832 //
5833 //
5834 // Remove the packet from the queue
5835 //
5836 pNextPacket = pPacket->pNext;
5837 *ppQueueHead = pNextPacket;
5838 if ( NULL == pNextPacket ) {
5839 *ppQueueTail = NULL;
5840 }
5841 pPacket->pNext = NULL;
5842
5843 //
5844 // Eliminate the need for IP4 and UDP4 specific routines by
5845 // connecting the token with the TX data control structure here.
5846 //
5847 // +--------------------+ +--------------------+
5848 // | ESL_IO_MGMT | | ESL_PACKET |
5849 // | | | |
5850 // | +---------------+ +----------------+ |
5851 // | | Token | | Buffer Length | |
5852 // | | TxData --> | Buffer Address | |
5853 // | | | +----------------+---+
5854 // | | Event | | Data Buffer |
5855 // +----+---------------+ | |
5856 // +--------------------+
5857 //
5858 // Compute the address of the TxData pointer in the token
5859 //
5860 pBuffer = (UINT8 *)&pIo->Token;
5861 pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
5862 ppTokenData = (VOID **)pBuffer;
5863
5864 //
5865 // Compute the address of the TX data control structure in the packet
5866 //
5867 // * EFI_IP4_TRANSMIT_DATA
5868 // * EFI_TCP4_TRANSMIT_DATA
5869 // * EFI_UDP4_TRANSMIT_DATA
5870 //
5871 pBuffer = (UINT8 *)pPacket;
5872 pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
5873
5874 //
5875 // Connect the token to the transmit data control structure
5876 //
5877 *ppTokenData = (VOID **)pBuffer;
5878
5879 //
5880 // Display the results
5881 //
5882 DEBUG (( DEBUG_TX | DEBUG_INFO,
5883 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5884 pIo,
5885 pPacket ));
5886
5887 //
5888 // Start the transmit operation
5889 //
5890 Status = pPort->pfnTxStart ( pPort->pProtocol.v,
5891 &pIo->Token );
5892 if ( !EFI_ERROR ( Status )) {
5893 //
5894 // Connect the structures
5895 //
5896 pIo->pPacket = pPacket;
5897
5898 //
5899 // +-------------+ +-------------+ +-------------+
5900 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5901 // +-------------+ +-------------+ +-------------+
5902 // ^
5903 // |
5904 // *ppFree: pPort->pTxFree or pTxOobFree
5905 //
5906 //
5907 // Remove the IO structure from the queue
5908 //
5909 *ppFree = pIo->pNext;
5910
5911 //
5912 // *ppActive: pPort->pTxActive or pTxOobActive
5913 // |
5914 // V
5915 // +-------------+ +-------------+ +-------------+
5916 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5917 // +-------------+ +-------------+ +-------------+
5918 //
5919 //
5920 // Mark this packet as active
5921 //
5922 pIo->pPacket = pPacket;
5923 pIo->pNext = *ppActive;
5924 *ppActive = pIo;
5925 }
5926 else {
5927 if ( EFI_SUCCESS == pSocket->TxError ) {
5928 pSocket->TxError = Status;
5929 }
5930
5931 //
5932 // Discard the transmit buffer
5933 //
5934 EslSocketPacketFree ( pPacket, DEBUG_TX );
5935 }
5936 }
5937
5938 DBG_EXIT ( );
5939 }