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