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