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