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