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