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