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