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