]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Tcp4.c
Merged socket development branch:
[mirror_edk2.git] / StdLib / EfiSocketLib / Tcp4.c
1 /** @file
2 Implement the TCP4 driver support for the socket layer.
3
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14 \section ConnectionManagement Connection Management
15
16 The ::EslTcp4Listen routine initially places the SOCK_STREAM or
17 SOCK_SEQPACKET socket into a listen state. When a remote machine
18 makes a connection to the socket, the TCPv4 network layer calls
19 ::EslTcp4ListenComplete to complete the connection processing.
20 EslTcp4ListenComplete manages the connections by placing them in
21 FIFO order in a queue to be serviced by the application. When the
22 number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
23 the new connection is closed. Eventually, the application indirectly
24 calls ::EslTcp4Accept to remove the next connection from the queue
25 and get the associated socket.
26
27 **/
28
29 #include "Socket.h"
30
31
32 /**
33 Attempt to connect to a remote TCP port
34
35 This routine starts the connection processing for a SOCK_STREAM
36 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
37 configures the local TCPv4 connection point and then attempts to
38 connect to a remote system. Upon completion, the
39 ::EslTcp4ConnectComplete routine gets called with the connection
40 status.
41
42 This routine is called by ::EslSocketConnect to initiate the TCPv4
43 network specific connect operations. The connection processing is
44 initiated by this routine and finished by ::EslTcp4ConnectComplete.
45 This pair of routines walks through the list of local TCPv4
46 connection points until a connection to the remote system is
47 made.
48
49 @param [in] pSocket Address of an ::ESL_SOCKET structure.
50
51 @retval EFI_SUCCESS The connection was successfully established.
52 @retval EFI_NOT_READY The connection is in progress, call this routine again.
53 @retval Others The connection attempt failed.
54
55 **/
56 EFI_STATUS
57 EslTcp4ConnectStart (
58 IN ESL_SOCKET * pSocket
59 );
60
61
62 /**
63 Process the connection attempt
64
65 A system has initiated a connection attempt with a socket in the
66 listen state. Attempt to complete the connection.
67
68 The TCPv4 layer calls this routine when a connection is made to
69 the socket in the listen state. See the
70 \ref ConnectionManagement section.
71
72 @param [in] Event The listen completion event
73
74 @param [in] pPort Address of an ::ESL_PORT structure.
75
76 **/
77 VOID
78 EslTcp4ListenComplete (
79 IN EFI_EVENT Event,
80 IN ESL_PORT * pPort
81 );
82
83
84 /**
85 Accept a network connection.
86
87 This routine waits for a network connection to the socket and
88 returns the remote network address to the caller if requested.
89
90 This routine is called by ::EslSocketAccept to handle the TCPv4 protocol
91 specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
92 See the \ref ConnectionManagement section.
93
94 @param [in] pSocket Address of an ::ESL_SOCKET structure.
95
96 @param [in] pSockAddr Address of a buffer to receive the remote
97 network address.
98
99 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
100 On output specifies the length of the
101 remote network address.
102
103 @retval EFI_SUCCESS Remote address is available
104 @retval Others Remote address not available
105
106 **/
107 EFI_STATUS
108 EslTcp4Accept (
109 IN ESL_SOCKET * pSocket,
110 IN struct sockaddr * pSockAddr,
111 IN OUT socklen_t * pSockAddrLength
112 )
113 {
114 ESL_PORT * pPort;
115 struct sockaddr_in * pRemoteAddress;
116 ESL_TCP4_CONTEXT * pTcp4;
117 UINT32 RemoteAddress;
118 EFI_STATUS Status;
119
120 DBG_ENTER ( );
121
122 //
123 // Validate the socket length
124 //
125 pRemoteAddress = (struct sockaddr_in *) pSockAddr;
126 if (( NULL == pSockAddrLength )
127 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {
128 //
129 // Invalid socket address
130 //
131 Status = EFI_INVALID_PARAMETER;
132 pSocket->errno = EINVAL;
133 DEBUG (( DEBUG_ACCEPT,
134 "ERROR - Invalid address length\r\n" ));
135 }
136 else {
137 //
138 // Assume success
139 //
140 Status = EFI_SUCCESS;
141
142 //
143 // Locate the address context
144 //
145 pPort = pSocket->pPortList;
146 pTcp4 = &pPort->Context.Tcp4;
147
148 //
149 // Fill-in the remote address structure
150 //
151 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));
152 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );
153 pRemoteAddress->sin_family = AF_INET;
154 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
155 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
156 RemoteAddress <<= 8;
157 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
158 RemoteAddress <<= 8;
159 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
160 RemoteAddress <<= 8;
161 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
162 pRemoteAddress->sin_addr.s_addr = RemoteAddress;
163 }
164
165 //
166 // Return the operation status
167 //
168 DBG_EXIT_STATUS ( Status );
169 return Status;
170 }
171
172
173 /**
174 Process the remote connection completion event.
175
176 This routine handles the completion of a connection attempt. It
177 releases the port (TCPv4 adapter connection) in the case of an
178 error and start a connection attempt on the next port. If the
179 connection attempt was successful then this routine releases all
180 of the other ports.
181
182 This routine is called by the TCPv4 layer when a connect request
183 completes. It sets the ESL_SOCKET::bConnected flag to notify the
184 ::EslTcp4ConnectComplete routine that the connection is available.
185 The flag is set when the connection is established or no more ports
186 exist in the list. The connection status is passed via
187 ESL_SOCKET::ConnectStatus.
188
189 @param [in] Event The connect completion event
190
191 @param [in] pPort Address of an ::ESL_PORT structure.
192
193 **/
194 VOID
195 EslTcp4ConnectComplete (
196 IN EFI_EVENT Event,
197 IN ESL_PORT * pPort
198 )
199 {
200 BOOLEAN bRemoveFirstPort;
201 BOOLEAN bRemovePorts;
202 ESL_PORT * pNextPort;
203 ESL_SOCKET * pSocket;
204 ESL_TCP4_CONTEXT * pTcp4;
205 EFI_STATUS Status;
206
207 DBG_ENTER ( );
208
209 //
210 // Locate the TCP context
211 //
212 pSocket = pPort->pSocket;
213 pTcp4 = &pPort->Context.Tcp4;
214
215 //
216 // Get the connection status
217 //
218 bRemoveFirstPort = FALSE;
219 bRemovePorts = FALSE;
220 Status = pTcp4->ConnectToken.CompletionToken.Status;
221 pSocket->ConnectStatus = Status;
222 if ( !EFI_ERROR ( Status )) {
223 //
224 // The connection was successful
225 //
226 DEBUG (( DEBUG_CONNECT,
227 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
228 pPort,
229 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
230 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
231 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
232 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
233 pTcp4->ConfigData.AccessPoint.RemotePort ));
234
235 //
236 // Remove the rest of the ports
237 //
238 bRemovePorts = TRUE;
239 }
240 else {
241 //
242 // The connection failed
243 //
244 DEBUG (( DEBUG_CONNECT,
245 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
246 pPort,
247 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
248 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
249 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
250 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
251 pTcp4->ConfigData.AccessPoint.RemotePort,
252 Status ));
253
254 //
255 // Close the current port
256 //
257 Status = EslSocketPortClose ( pPort );
258 if ( !EFI_ERROR ( Status )) {
259 DEBUG (( DEBUG_CONNECT,
260 "0x%08x: Port closed\r\n",
261 pPort ));
262 }
263 else {
264 DEBUG (( DEBUG_CONNECT,
265 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
266 pPort,
267 Status ));
268 }
269
270 //
271 // Try to connect using the next port
272 //
273 Status = EslTcp4ConnectStart ( pSocket );
274 if ( EFI_NOT_READY != Status ) {
275 pSocket->ConnectStatus = Status;
276 bRemoveFirstPort = TRUE;
277 }
278 }
279
280 //
281 // Remove the ports if necessary
282 //
283 if ( bRemoveFirstPort || bRemovePorts ) {
284 //
285 // Remove the first port if necessary
286 //
287 pPort = pSocket->pPortList;
288 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {
289 pPort = pPort->pLinkSocket;
290 }
291
292 //
293 // Remove the rest of the list
294 //
295 while ( NULL != pPort ) {
296 pNextPort = pPort->pLinkSocket;
297 EslSocketPortClose ( pPort );
298 if ( !EFI_ERROR ( Status )) {
299 DEBUG (( DEBUG_CONNECT,
300 "0x%08x: Port closed\r\n",
301 pPort ));
302 }
303 else {
304 DEBUG (( DEBUG_CONNECT,
305 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
306 pPort,
307 Status ));
308 }
309 pPort = pNextPort;
310 }
311
312 //
313 // Notify the poll routine
314 //
315 pSocket->bConnected = TRUE;
316 }
317
318 DBG_EXIT ( );
319 }
320
321
322 /**
323 Poll for completion of the connection attempt.
324
325 This routine polls the ESL_SOCKET::bConnected flag to determine
326 when the connection attempt is complete.
327
328 This routine is called from ::EslSocketConnect to determine when
329 the connection is complete. The ESL_SOCKET::bConnected flag is
330 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
331 a connection or runs out of local network adapters. This routine
332 gets the connection status from ESL_SOCKET::ConnectStatus.
333
334 @param [in] pSocket Address of an ::ESL_SOCKET structure.
335
336 @retval EFI_SUCCESS The connection was successfully established.
337 @retval EFI_NOT_READY The connection is in progress, call this routine again.
338 @retval Others The connection attempt failed.
339
340 **/
341 EFI_STATUS
342 EslTcp4ConnectPoll (
343 IN ESL_SOCKET * pSocket
344 )
345 {
346 EFI_STATUS Status;
347
348 DBG_ENTER ( );
349
350 //
351 // Determine if the connection is complete
352 //
353 if ( !pSocket->bConnected ) {
354 //
355 // Not connected
356 //
357 pSocket->errno = EAGAIN;
358 Status = EFI_NOT_READY;
359 }
360 else {
361 //
362 // The connection processing is complete
363 //
364 pSocket->bConnected = FALSE;
365
366 //
367 // Translate the connection status
368 //
369 Status = pSocket->ConnectStatus;
370 switch ( Status ) {
371 default:
372 case EFI_DEVICE_ERROR:
373 pSocket->errno = EIO;
374 break;
375
376 case EFI_ABORTED:
377 pSocket->errno = ECONNREFUSED;
378 break;
379
380 case EFI_INVALID_PARAMETER:
381 pSocket->errno = EINVAL;
382 break;
383
384 case EFI_NO_MAPPING:
385 case EFI_NO_RESPONSE:
386 pSocket->errno = EHOSTUNREACH;
387 break;
388
389 case EFI_NO_MEDIA:
390 pSocket->errno = ENETDOWN;
391 break;
392
393 case EFI_OUT_OF_RESOURCES:
394 pSocket->errno = ENOMEM;
395 break;
396
397 case EFI_SUCCESS:
398 pSocket->errno = 0;
399 pSocket->bConfigured = TRUE;
400 break;
401
402 case EFI_TIMEOUT:
403 pSocket->errno = ETIMEDOUT;
404 break;
405
406 case EFI_UNSUPPORTED:
407 pSocket->errno = ENOTSUP;
408 break;
409
410 case 0x80000069:
411 pSocket->errno = ECONNRESET;
412 break;
413 }
414 }
415
416 //
417 // Return the initialization status
418 //
419 DBG_EXIT_STATUS ( Status );
420 return Status;
421 }
422
423
424 /**
425 Attempt to connect to a remote TCP port
426
427 This routine starts the connection processing for a SOCK_STREAM
428 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
429 configures the local TCPv4 connection point and then attempts to
430 connect to a remote system. Upon completion, the
431 ::EslTcp4ConnectComplete routine gets called with the connection
432 status.
433
434 This routine is called by ::EslSocketConnect to initiate the TCPv4
435 network specific connect operations. The connection processing is
436 initiated by this routine and finished by ::EslTcp4ConnectComplete.
437 This pair of routines walks through the list of local TCPv4
438 connection points until a connection to the remote system is
439 made.
440
441 @param [in] pSocket Address of an ::ESL_SOCKET structure.
442
443 @retval EFI_SUCCESS The connection was successfully established.
444 @retval EFI_NOT_READY The connection is in progress, call this routine again.
445 @retval Others The connection attempt failed.
446
447 **/
448 EFI_STATUS
449 EslTcp4ConnectStart (
450 IN ESL_SOCKET * pSocket
451 )
452 {
453 ESL_PORT * pPort;
454 ESL_TCP4_CONTEXT * pTcp4;
455 EFI_TCP4_PROTOCOL * pTcp4Protocol;
456 EFI_STATUS Status;
457
458 DBG_ENTER ( );
459
460 //
461 // Determine if any more local adapters are available
462 //
463 pPort = pSocket->pPortList;
464 if ( NULL != pPort ) {
465 //
466 // Configure the port
467 //
468 pTcp4 = &pPort->Context.Tcp4;
469 pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
470 pTcp4->ConfigData.TimeToLive = 255;
471 pTcp4Protocol = pPort->pProtocol.TCPv4;
472 Status = pTcp4Protocol->Configure ( pTcp4Protocol,
473 &pTcp4->ConfigData );
474 if ( EFI_ERROR ( Status )) {
475 DEBUG (( DEBUG_CONNECT,
476 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
477 Status ));
478 switch ( Status ) {
479 case EFI_ACCESS_DENIED:
480 pSocket->errno = EACCES;
481 break;
482
483 default:
484 case EFI_DEVICE_ERROR:
485 pSocket->errno = EIO;
486 break;
487
488 case EFI_INVALID_PARAMETER:
489 pSocket->errno = EADDRNOTAVAIL;
490 break;
491
492 case EFI_NO_MAPPING:
493 pSocket->errno = EAFNOSUPPORT;
494 break;
495
496 case EFI_OUT_OF_RESOURCES:
497 pSocket->errno = ENOBUFS;
498 break;
499
500 case EFI_UNSUPPORTED:
501 pSocket->errno = EOPNOTSUPP;
502 break;
503 }
504 }
505 else {
506 DEBUG (( DEBUG_CONNECT,
507 "0x%08x: Port configured\r\n",
508 pPort ));
509 pPort->bConfigured = TRUE;
510
511 //
512 // Attempt the connection to the remote system
513 //
514 Status = pTcp4Protocol->Connect ( pTcp4Protocol,
515 &pTcp4->ConnectToken );
516 if ( !EFI_ERROR ( Status )) {
517 //
518 // Connection in progress
519 //
520 pSocket->errno = EINPROGRESS;
521 Status = EFI_NOT_READY;
522 DEBUG (( DEBUG_CONNECT,
523 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
524 pPort,
525 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
526 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
527 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
528 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
529 pTcp4->ConfigData.AccessPoint.RemotePort ));
530 }
531 else {
532 //
533 // Connection error
534 //
535 DEBUG (( DEBUG_CONNECT,
536 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
537 pPort,
538 Status ));
539 //
540 // Determine the errno value
541 //
542 switch ( Status ) {
543 default:
544 pSocket->errno = EIO;
545 break;
546
547 case EFI_OUT_OF_RESOURCES:
548 pSocket->errno = ENOBUFS;
549 break;
550
551 case EFI_TIMEOUT:
552 pSocket->errno = ETIMEDOUT;
553 break;
554
555 case EFI_NETWORK_UNREACHABLE:
556 pSocket->errno = ENETDOWN;
557 break;
558
559 case EFI_HOST_UNREACHABLE:
560 pSocket->errno = EHOSTUNREACH;
561 break;
562
563 case EFI_PORT_UNREACHABLE:
564 case EFI_PROTOCOL_UNREACHABLE:
565 case EFI_CONNECTION_REFUSED:
566 pSocket->errno = ECONNREFUSED;
567 break;
568
569 case EFI_CONNECTION_RESET:
570 pSocket->errno = ECONNRESET;
571 break;
572 }
573 }
574 }
575 }
576 else {
577 //
578 // No more local adapters available
579 //
580 pSocket->errno = ENETUNREACH;
581 Status = EFI_NO_RESPONSE;
582 }
583
584 //
585 // Return the operation status
586 //
587 DBG_EXIT_STATUS ( Status );
588 return Status;
589 }
590
591
592 /**
593 Establish the known port to listen for network connections.
594
595 This routine places the port into a state that enables connection
596 attempts.
597
598 This routine is called by ::EslSocketListen to handle the network
599 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
600 sockets. See the \ref ConnectionManagement section.
601
602 @param [in] pSocket Address of an ::ESL_SOCKET structure.
603
604 @retval EFI_SUCCESS - Socket successfully created
605 @retval Other - Failed to enable the socket for listen
606
607 **/
608 EFI_STATUS
609 EslTcp4Listen (
610 IN ESL_SOCKET * pSocket
611 )
612 {
613 ESL_PORT * pNextPort;
614 ESL_PORT * pPort;
615 ESL_TCP4_CONTEXT * pTcp4;
616 EFI_TCP4_PROTOCOL * pTcp4Protocol;
617 EFI_STATUS Status;
618
619 DBG_ENTER ( );
620
621 //
622 // Verify the socket layer synchronization
623 //
624 VERIFY_TPL ( TPL_SOCKETS );
625
626 //
627 // Use for/break instead of goto
628 //
629 for ( ; ; ) {
630 //
631 // Assume no ports are available
632 //
633 pSocket->errno = EOPNOTSUPP;
634 Status = EFI_NOT_READY;
635
636 //
637 // Walk the list of ports
638 //
639 pPort = pSocket->pPortList;
640 while ( NULL != pPort ) {
641 //
642 // Assume success
643 //
644 pSocket->errno = 0;
645
646 //
647 // Use for/break insteak of goto
648 //
649 for ( ; ; ) {
650 //
651 // Create the listen completion event
652 //
653 pTcp4 = &pPort->Context.Tcp4;
654 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
655 TPL_SOCKETS,
656 (EFI_EVENT_NOTIFY)EslTcp4ListenComplete,
657 pPort,
658 &pTcp4->ListenToken.CompletionToken.Event );
659 if ( EFI_ERROR ( Status )) {
660 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
661 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
662 Status ));
663 pSocket->errno = ENOMEM;
664 break;
665 }
666 DEBUG (( DEBUG_POOL,
667 "0x%08x: Created listen completion event\r\n",
668 pTcp4->ListenToken.CompletionToken.Event ));
669
670 //
671 // Configure the port
672 //
673 pTcp4Protocol = pPort->pProtocol.TCPv4;
674 Status = pTcp4Protocol->Configure ( pTcp4Protocol,
675 &pTcp4->ConfigData );
676 if ( EFI_ERROR ( Status )) {
677 DEBUG (( DEBUG_LISTEN,
678 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
679 Status ));
680 switch ( Status ) {
681 case EFI_ACCESS_DENIED:
682 pSocket->errno = EACCES;
683 break;
684
685 default:
686 case EFI_DEVICE_ERROR:
687 pSocket->errno = EIO;
688 break;
689
690 case EFI_INVALID_PARAMETER:
691 pSocket->errno = EADDRNOTAVAIL;
692 break;
693
694 case EFI_NO_MAPPING:
695 pSocket->errno = EAFNOSUPPORT;
696 break;
697
698 case EFI_OUT_OF_RESOURCES:
699 pSocket->errno = ENOBUFS;
700 break;
701
702 case EFI_UNSUPPORTED:
703 pSocket->errno = EOPNOTSUPP;
704 break;
705 }
706 break;
707 }
708 DEBUG (( DEBUG_LISTEN,
709 "0x%08x: Port configured\r\n",
710 pPort ));
711 pPort->bConfigured = TRUE;
712
713 //
714 // Start the listen operation on the port
715 //
716 Status = pTcp4Protocol->Accept ( pTcp4Protocol,
717 &pTcp4->ListenToken );
718 if ( EFI_ERROR ( Status )) {
719 DEBUG (( DEBUG_LISTEN,
720 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
721 Status ));
722 switch ( Status ) {
723 case EFI_ACCESS_DENIED:
724 pSocket->errno = EACCES;
725 break;
726
727 default:
728 case EFI_DEVICE_ERROR:
729 pSocket->errno = EIO;
730 break;
731
732 case EFI_INVALID_PARAMETER:
733 pSocket->errno = EADDRNOTAVAIL;
734 break;
735
736 case EFI_NOT_STARTED:
737 pSocket->errno = ENETDOWN;
738 break;
739
740 case EFI_OUT_OF_RESOURCES:
741 pSocket->errno = ENOBUFS;
742 break;
743 }
744 break;
745 }
746 DEBUG (( DEBUG_LISTEN,
747 "0x%08x: Listen pending on Port\r\n",
748 pPort ));
749
750 //
751 // Listen is pending on this port
752 //
753 break;
754 }
755
756 //
757 // Get the next port
758 //
759 pNextPort = pPort->pLinkSocket;
760
761 //
762 // Close the port upon error
763 //
764 if ( EFI_ERROR ( Status )) {
765 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
766 }
767
768 //
769 // Set the next port
770 //
771 pPort = pNextPort;
772 }
773
774 //
775 // Determine if any ports are in the listen state
776 //
777 if ( NULL == pSocket->pPortList ) {
778 //
779 // No ports in the listen state
780 //
781 pSocket->MaxFifoDepth = 0;
782
783 //
784 // Return the last error detected
785 //
786 break;
787 }
788
789 //
790 // Mark the socket as configured
791 //
792 pSocket->bConfigured = TRUE;
793
794 //
795 // All done
796 //
797 DEBUG (( DEBUG_LISTEN,
798 "0x%08x: pSocket - Listen pending on socket\r\n",
799 pSocket ));
800 break;
801 }
802
803 //
804 // Return the operation status
805 //
806 DBG_EXIT_STATUS ( Status );
807 return Status;
808 }
809
810
811 /**
812 Process the connection attempt
813
814 A system has initiated a connection attempt with a socket in the
815 listen state. Attempt to complete the connection.
816
817 The TCPv4 layer calls this routine when a connection is made to
818 the socket in the listen state. See the
819 \ref ConnectionManagement section.
820
821 @param [in] Event The listen completion event
822
823 @param [in] pPort Address of an ::ESL_PORT structure.
824
825 **/
826 VOID
827 EslTcp4ListenComplete (
828 IN EFI_EVENT Event,
829 IN ESL_PORT * pPort
830 )
831 {
832 EFI_HANDLE ChildHandle;
833 struct sockaddr_in LocalAddress;
834 EFI_TCP4_CONFIG_DATA * pConfigData;
835 ESL_LAYER * pLayer;
836 ESL_PORT * pNewPort;
837 ESL_SOCKET * pNewSocket;
838 ESL_SOCKET * pSocket;
839 ESL_TCP4_CONTEXT * pTcp4;
840 EFI_TCP4_PROTOCOL * pTcp4Protocol;
841 EFI_STATUS Status;
842 EFI_HANDLE TcpPortHandle;
843 EFI_STATUS TempStatus;
844
845 DBG_ENTER ( );
846 VERIFY_AT_TPL ( TPL_SOCKETS );
847
848 //
849 // Assume success
850 //
851 Status = EFI_SUCCESS;
852
853 //
854 // Determine if this connection fits into the connection FIFO
855 //
856 pSocket = pPort->pSocket;
857 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;
858 if (( SOCKET_STATE_LISTENING == pSocket->State )
859 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {
860 //
861 // Allocate a socket for this connection
862 //
863 ChildHandle = NULL;
864 pLayer = &mEslLayer;
865 Status = EslSocketAllocate ( &ChildHandle,
866 DEBUG_CONNECTION,
867 &pNewSocket );
868 if ( !EFI_ERROR ( Status )) {
869 //
870 // Clone the socket parameters
871 //
872 pNewSocket->pApi = pSocket->pApi;
873 pNewSocket->Domain = pSocket->Domain;
874 pNewSocket->Protocol = pSocket->Protocol;
875 pNewSocket->Type = pSocket->Type;
876
877 //
878 // Build the local address
879 //
880 pTcp4 = &pPort->Context.Tcp4;
881 LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
882 LocalAddress.sin_family = AF_INET;
883 LocalAddress.sin_port = 0;
884 LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];
885
886 //
887 // Allocate a port for this connection
888 // Note in this instance Configure may not be called with NULL!
889 //
890 Status = EslSocketPortAllocate ( pNewSocket,
891 pPort->pService,
892 TcpPortHandle,
893 (struct sockaddr *)&LocalAddress,
894 FALSE,
895 DEBUG_CONNECTION,
896 &pNewPort );
897 if ( !EFI_ERROR ( Status )) {
898 //
899 // Restart the listen operation on the port
900 //
901 pTcp4Protocol = pPort->pProtocol.TCPv4;
902 Status = pTcp4Protocol->Accept ( pTcp4Protocol,
903 &pTcp4->ListenToken );
904
905 //
906 // Close the TCP port using SocketClose
907 //
908 TcpPortHandle = NULL;
909 pTcp4 = &pNewPort->Context.Tcp4;
910
911 //
912 // Check for an accept call error
913 //
914 if ( !EFI_ERROR ( Status )) {
915 //
916 // Get the port configuration
917 //
918 pNewPort->bConfigured = TRUE;
919 pConfigData = &pTcp4->ConfigData;
920 pConfigData->ControlOption = &pTcp4->Option;
921 pTcp4Protocol = pNewPort->pProtocol.TCPv4;
922 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,
923 NULL,
924 pConfigData,
925 NULL,
926 NULL,
927 NULL );
928 if ( !EFI_ERROR ( Status )) {
929 //
930 // Add the new socket to the connection FIFO
931 //
932 if ( NULL == pSocket->pFifoTail ) {
933 //
934 // First connection
935 //
936 pSocket->pFifoHead = pNewSocket;
937 }
938 else {
939 //
940 // Add to end of list.
941 //
942 pSocket->pFifoTail->pNextConnection = pNewSocket;
943 }
944 pSocket->pFifoTail = pNewSocket;
945 pSocket->FifoDepth += 1;
946
947 //
948 // Update the socket state
949 //
950 pNewSocket->State = SOCKET_STATE_IN_FIFO;
951
952 //
953 // Log the connection
954 //
955 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
956 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
957 pNewSocket,
958 pConfigData->AccessPoint.StationAddress.Addr[0],
959 pConfigData->AccessPoint.StationAddress.Addr[1],
960 pConfigData->AccessPoint.StationAddress.Addr[2],
961 pConfigData->AccessPoint.StationAddress.Addr[3],
962 pConfigData->AccessPoint.StationPort,
963 pConfigData->AccessPoint.RemoteAddress.Addr[0],
964 pConfigData->AccessPoint.RemoteAddress.Addr[1],
965 pConfigData->AccessPoint.RemoteAddress.Addr[2],
966 pConfigData->AccessPoint.RemoteAddress.Addr[3],
967 pConfigData->AccessPoint.RemotePort ));
968 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
969 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
970 pSocket,
971 pNewSocket,
972 pSocket->FifoDepth ));
973
974 //
975 // Start the receive operation
976 //
977 EslSocketRxStart ( pNewPort );
978 }
979 else {
980 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
981 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
982 pNewPort,
983 Status ));
984 }
985 }
986 else {
987 //
988 // The listen failed on this port
989 //
990 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,
991 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
992 pPort,
993 Status ));
994
995 //
996 // Close the listening port
997 //
998 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
999 }
1000 }
1001
1002 //
1003 // Done with the socket if necessary
1004 //
1005 if ( EFI_ERROR ( Status )) {
1006 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,
1007 TRUE,
1008 &pSocket->errno );
1009 ASSERT ( EFI_SUCCESS == TempStatus );
1010 }
1011 }
1012 }
1013 else {
1014 DEBUG (( DEBUG_CONNECTION,
1015 "0x%08x: Socket FIFO full, connection refused\r\n",
1016 pSocket ));
1017
1018 //
1019 // The FIFO is full or the socket is in the wrong state
1020 //
1021 Status = EFI_BUFFER_TOO_SMALL;
1022 }
1023
1024 //
1025 // Close the connection if necessary
1026 //
1027 if (( EFI_ERROR ( Status ))
1028 && ( NULL == TcpPortHandle )) {
1029 //
1030 // TODO: Finish this code path
1031 // The new connection does not fit into the connection FIFO
1032 //
1033 // Process:
1034 // Call close
1035 // Release the resources
1036
1037 }
1038
1039 DBG_EXIT ( );
1040 }
1041
1042
1043 /**
1044 Get the local socket address.
1045
1046 This routine returns the IPv4 address and TCP port number associated
1047 with the local socket.
1048
1049 This routine is called by ::EslSocketGetLocalAddress to determine the
1050 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1051
1052 @param [in] pPort Address of an ::ESL_PORT structure.
1053
1054 @param [out] pSockAddr Network address to receive the local system address
1055
1056 **/
1057 VOID
1058 EslTcp4LocalAddressGet (
1059 IN ESL_PORT * pPort,
1060 OUT struct sockaddr * pSockAddr
1061 )
1062 {
1063 struct sockaddr_in * pLocalAddress;
1064 ESL_TCP4_CONTEXT * pTcp4;
1065
1066 DBG_ENTER ( );
1067
1068 //
1069 // Return the local address
1070 //
1071 pTcp4 = &pPort->Context.Tcp4;
1072 pLocalAddress = (struct sockaddr_in *)pSockAddr;
1073 pLocalAddress->sin_family = AF_INET;
1074 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
1075 CopyMem ( &pLocalAddress->sin_addr,
1076 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
1077 sizeof ( pLocalAddress->sin_addr ));
1078
1079 DBG_EXIT ( );
1080 }
1081
1082
1083 /**
1084 Set the local port address.
1085
1086 This routine sets the local port address.
1087
1088 This support routine is called by ::EslSocketPortAllocate.
1089
1090 @param [in] pPort Address of an ESL_PORT structure
1091 @param [in] pSockAddr Address of a sockaddr structure that contains the
1092 connection point on the local machine. An IPv4 address
1093 of INADDR_ANY specifies that the connection is made to
1094 all of the network stacks on the platform. Specifying a
1095 specific IPv4 address restricts the connection to the
1096 network stack supporting that address. Specifying zero
1097 for the port causes the network layer to assign a port
1098 number from the dynamic range. Specifying a specific
1099 port number causes the network layer to use that port.
1100
1101 @param [in] bBindTest TRUE = run bind testing
1102
1103 @retval EFI_SUCCESS The operation was successful
1104
1105 **/
1106 EFI_STATUS
1107 EslTcp4LocalAddressSet (
1108 IN ESL_PORT * pPort,
1109 IN CONST struct sockaddr * pSockAddr,
1110 IN BOOLEAN bBindTest
1111 )
1112 {
1113 EFI_TCP4_ACCESS_POINT * pAccessPoint;
1114 CONST struct sockaddr_in * pIpAddress;
1115 CONST UINT8 * pIpv4Address;
1116 EFI_STATUS Status;
1117
1118 DBG_ENTER ( );
1119
1120 //
1121 // Validate the address
1122 //
1123 pIpAddress = (struct sockaddr_in *)pSockAddr;
1124 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
1125 //
1126 // The local address must not be the broadcast address
1127 //
1128 Status = EFI_INVALID_PARAMETER;
1129 pPort->pSocket->errno = EADDRNOTAVAIL;
1130 }
1131 else {
1132 //
1133 // Set the local address
1134 //
1135 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
1136 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
1137 pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];
1138 pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];
1139 pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];
1140 pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];
1141
1142 //
1143 // Determine if the default address is used
1144 //
1145 pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
1146
1147 //
1148 // Set the subnet mask
1149 //
1150 if ( pAccessPoint->UseDefaultAddress ) {
1151 pAccessPoint->SubnetMask.Addr[0] = 0;
1152 pAccessPoint->SubnetMask.Addr[1] = 0;
1153 pAccessPoint->SubnetMask.Addr[2] = 0;
1154 pAccessPoint->SubnetMask.Addr[3] = 0;
1155 }
1156 else {
1157 pAccessPoint->SubnetMask.Addr[0] = 0xff;
1158 pAccessPoint->SubnetMask.Addr[1] = 0xff;
1159 pAccessPoint->SubnetMask.Addr[2] = 0xff;
1160 pAccessPoint->SubnetMask.Addr[3] = 0xff;
1161 }
1162
1163 //
1164 // Validate the IP address
1165 //
1166 pAccessPoint->StationPort = 0;
1167 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
1168 : EFI_SUCCESS;
1169 if ( !EFI_ERROR ( Status )) {
1170 //
1171 // Set the port number
1172 //
1173 pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );
1174
1175 //
1176 // Display the local address
1177 //
1178 DEBUG (( DEBUG_BIND,
1179 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1180 pPort,
1181 pAccessPoint->StationAddress.Addr[0],
1182 pAccessPoint->StationAddress.Addr[1],
1183 pAccessPoint->StationAddress.Addr[2],
1184 pAccessPoint->StationAddress.Addr[3],
1185 pAccessPoint->StationPort ));
1186 }
1187 }
1188
1189 //
1190 // Return the operation status
1191 //
1192 DBG_EXIT_STATUS ( Status );
1193 return Status;
1194 }
1195
1196
1197 /**
1198 Free a receive packet
1199
1200 This routine performs the network specific operations necessary
1201 to free a receive packet.
1202
1203 This routine is called by ::EslSocketPortCloseTxDone to free a
1204 receive packet.
1205
1206 @param [in] pPacket Address of an ::ESL_PACKET structure.
1207 @param [in, out] pRxBytes Address of the count of RX bytes
1208
1209 **/
1210 VOID
1211 EslTcp4PacketFree (
1212 IN ESL_PACKET * pPacket,
1213 IN OUT size_t * pRxBytes
1214 )
1215 {
1216 DBG_ENTER ( );
1217
1218 //
1219 // Account for the receive bytes
1220 //
1221 *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;
1222 DBG_EXIT ( );
1223 }
1224
1225
1226 /**
1227 Initialize the network specific portions of an ::ESL_PORT structure.
1228
1229 This routine initializes the network specific portions of an
1230 ::ESL_PORT structure for use by the socket.
1231
1232 This support routine is called by ::EslSocketPortAllocate
1233 to connect the socket with the underlying network adapter
1234 running the TCPv4 protocol.
1235
1236 @param [in] pPort Address of an ESL_PORT structure
1237 @param [in] DebugFlags Flags for debug messages
1238
1239 @retval EFI_SUCCESS - Socket successfully created
1240
1241 **/
1242 EFI_STATUS
1243 EslTcp4PortAllocate (
1244 IN ESL_PORT * pPort,
1245 IN UINTN DebugFlags
1246 )
1247 {
1248 EFI_TCP4_ACCESS_POINT * pAccessPoint;
1249 ESL_SOCKET * pSocket;
1250 ESL_TCP4_CONTEXT * pTcp4;
1251 EFI_STATUS Status;
1252
1253 DBG_ENTER ( );
1254
1255 //
1256 // Use for/break instead of goto
1257 for ( ; ; ) {
1258 //
1259 // Allocate the close event
1260 //
1261 pSocket = pPort->pSocket;
1262 pTcp4 = &pPort->Context.Tcp4;
1263 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1264 TPL_SOCKETS,
1265 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
1266 pPort,
1267 &pTcp4->CloseToken.CompletionToken.Event);
1268 if ( EFI_ERROR ( Status )) {
1269 DEBUG (( DEBUG_ERROR | DebugFlags,
1270 "ERROR - Failed to create the close event, Status: %r\r\n",
1271 Status ));
1272 pSocket->errno = ENOMEM;
1273 break;
1274 }
1275 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1276 "0x%08x: Created close event\r\n",
1277 pTcp4->CloseToken.CompletionToken.Event ));
1278
1279 //
1280 // Allocate the connection event
1281 //
1282 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1283 TPL_SOCKETS,
1284 (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,
1285 pPort,
1286 &pTcp4->ConnectToken.CompletionToken.Event);
1287 if ( EFI_ERROR ( Status )) {
1288 DEBUG (( DEBUG_ERROR | DebugFlags,
1289 "ERROR - Failed to create the connect event, Status: %r\r\n",
1290 Status ));
1291 pSocket->errno = ENOMEM;
1292 break;
1293 }
1294 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1295 "0x%08x: Created connect event\r\n",
1296 pTcp4->ConnectToken.CompletionToken.Event ));
1297
1298 //
1299 // Initialize the port
1300 //
1301 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );
1302 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );
1303 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );
1304
1305 //
1306 // Save the cancel, receive and transmit addresses
1307 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1308 //
1309 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;
1310 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;
1311 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;
1312 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;
1313
1314 //
1315 // Set the configuration flags
1316 //
1317 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
1318 pAccessPoint->ActiveFlag = FALSE;
1319 pTcp4->ConfigData.TimeToLive = 255;
1320 break;
1321 }
1322
1323 //
1324 // Return the operation status
1325 //
1326 DBG_EXIT_STATUS ( Status );
1327 return Status;
1328 }
1329
1330
1331 /**
1332 Close a TCP4 port.
1333
1334 This routine releases the network specific resources allocated by
1335 ::EslTcp4PortAllocate.
1336
1337 This routine is called by ::EslSocketPortClose.
1338 See the \ref PortCloseStateMachine section.
1339
1340 @param [in] pPort Address of an ::ESL_PORT structure.
1341
1342 @retval EFI_SUCCESS The port is closed
1343 @retval other Port close error
1344
1345 **/
1346 EFI_STATUS
1347 EslTcp4PortClose (
1348 IN ESL_PORT * pPort
1349 )
1350 {
1351 UINTN DebugFlags;
1352 ESL_TCP4_CONTEXT * pTcp4;
1353 EFI_STATUS Status;
1354
1355 DBG_ENTER ( );
1356
1357 //
1358 // Locate the port in the socket list
1359 //
1360 Status = EFI_SUCCESS;
1361 DebugFlags = pPort->DebugFlags;
1362 pTcp4 = &pPort->Context.Tcp4;
1363
1364 //
1365 // Done with the connect event
1366 //
1367 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {
1368 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );
1369 if ( !EFI_ERROR ( Status )) {
1370 DEBUG (( DebugFlags | DEBUG_POOL,
1371 "0x%08x: Closed connect event\r\n",
1372 pTcp4->ConnectToken.CompletionToken.Event ));
1373 }
1374 else {
1375 DEBUG (( DEBUG_ERROR | DebugFlags,
1376 "ERROR - Failed to close the connect event, Status: %r\r\n",
1377 Status ));
1378 ASSERT ( EFI_SUCCESS == Status );
1379 }
1380 }
1381
1382 //
1383 // Done with the close event
1384 //
1385 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {
1386 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );
1387 if ( !EFI_ERROR ( Status )) {
1388 DEBUG (( DebugFlags | DEBUG_POOL,
1389 "0x%08x: Closed close event\r\n",
1390 pTcp4->CloseToken.CompletionToken.Event ));
1391 }
1392 else {
1393 DEBUG (( DEBUG_ERROR | DebugFlags,
1394 "ERROR - Failed to close the close event, Status: %r\r\n",
1395 Status ));
1396 ASSERT ( EFI_SUCCESS == Status );
1397 }
1398 }
1399
1400 //
1401 // Done with the listen completion event
1402 //
1403 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {
1404 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );
1405 if ( !EFI_ERROR ( Status )) {
1406 DEBUG (( DebugFlags | DEBUG_POOL,
1407 "0x%08x: Closed listen completion event\r\n",
1408 pTcp4->ListenToken.CompletionToken.Event ));
1409 }
1410 else {
1411 DEBUG (( DEBUG_ERROR | DebugFlags,
1412 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1413 Status ));
1414 ASSERT ( EFI_SUCCESS == Status );
1415 }
1416 }
1417
1418 //
1419 // Return the operation status
1420 //
1421 DBG_EXIT_STATUS ( Status );
1422 return Status;
1423 }
1424
1425
1426 /**
1427 Perform the network specific close operation on the port.
1428
1429 This routine performs a cancel operations on the TCPv4 port to
1430 shutdown the receive operations on the port.
1431
1432 This routine is called by the ::EslSocketPortCloseTxDone
1433 routine after the port completes all of the transmission.
1434
1435 @param [in] pPort Address of an ::ESL_PORT structure.
1436
1437 @retval EFI_SUCCESS The port is closed, not normally returned
1438 @retval EFI_NOT_READY The port is still closing
1439 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1440 most likely the routine was called already.
1441
1442 **/
1443 EFI_STATUS
1444 EslTcp4PortCloseOp (
1445 IN ESL_PORT * pPort
1446 )
1447 {
1448 ESL_TCP4_CONTEXT * pTcp4;
1449 EFI_TCP4_PROTOCOL * pTcp4Protocol;
1450 EFI_STATUS Status;
1451
1452 DBG_ENTER ( );
1453
1454 //
1455 // Close the configured port
1456 //
1457 Status = EFI_SUCCESS;
1458 pTcp4 = &pPort->Context.Tcp4;
1459 pTcp4Protocol = pPort->pProtocol.TCPv4;
1460 pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;
1461 Status = pTcp4Protocol->Close ( pTcp4Protocol,
1462 &pTcp4->CloseToken );
1463 if ( !EFI_ERROR ( Status )) {
1464 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
1465 "0x%08x: Port close started\r\n",
1466 pPort ));
1467 }
1468 else {
1469 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
1470 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1471 pPort,
1472 Status ));
1473 }
1474
1475 //
1476 // Return the operation status
1477 //
1478 DBG_EXIT_STATUS ( Status );
1479 return Status;
1480 }
1481
1482
1483 /**
1484 Receive data from a network connection.
1485
1486 This routine attempts to return buffered data to the caller. The
1487 data is removed from the urgent queue if the message flag MSG_OOB
1488 is specified, otherwise data is removed from the normal queue.
1489 See the \ref ReceiveEngine section.
1490
1491 This routine is called by ::EslSocketReceive to handle the network
1492 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1493 sockets.
1494
1495 @param [in] pPort Address of an ::ESL_PORT structure.
1496
1497 @param [in] pPacket Address of an ::ESL_PACKET structure.
1498
1499 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1500
1501 @param [in] BufferLength Length of the the buffer
1502
1503 @param [in] pBuffer Address of a buffer to receive the data.
1504
1505 @param [in] pDataLength Number of received data bytes in the buffer.
1506
1507 @param [out] pAddress Network address to receive the remote system address
1508
1509 @param [out] pSkipBytes Address to receive the number of bytes skipped
1510
1511 @return Returns the address of the next free byte in the buffer.
1512
1513 **/
1514 UINT8 *
1515 EslTcp4Receive (
1516 IN ESL_PORT * pPort,
1517 IN ESL_PACKET * pPacket,
1518 IN BOOLEAN * pbConsumePacket,
1519 IN size_t BufferLength,
1520 IN UINT8 * pBuffer,
1521 OUT size_t * pDataLength,
1522 OUT struct sockaddr * pAddress,
1523 OUT size_t * pSkipBytes
1524 )
1525 {
1526 size_t DataLength;
1527 struct sockaddr_in * pRemoteAddress;
1528 ESL_TCP4_CONTEXT * pTcp4;
1529
1530 DBG_ENTER ( );
1531
1532 //
1533 // Return the remote system address if requested
1534 //
1535 if ( NULL != pAddress ) {
1536 //
1537 // Build the remote address
1538 //
1539 pTcp4 = &pPort->Context.Tcp4;
1540 DEBUG (( DEBUG_RX,
1541 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1542 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1543 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
1544 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
1545 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
1546 pTcp4->ConfigData.AccessPoint.RemotePort ));
1547 pRemoteAddress = (struct sockaddr_in *)pAddress;
1548 CopyMem ( &pRemoteAddress->sin_addr,
1549 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1550 sizeof ( pRemoteAddress->sin_addr ));
1551 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
1552 }
1553
1554 //
1555 // Determine the amount of received data
1556 //
1557 DataLength = pPacket->ValidBytes;
1558 if ( BufferLength < DataLength ) {
1559 DataLength = BufferLength;
1560 }
1561
1562 //
1563 // Move the data into the buffer
1564 //
1565 DEBUG (( DEBUG_RX,
1566 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1567 pPort,
1568 pPacket,
1569 pBuffer,
1570 DataLength ));
1571 CopyMem ( pBuffer, pPacket->pBuffer, DataLength );
1572
1573 //
1574 // Determine if the data is being read
1575 //
1576 if ( *pbConsumePacket ) {
1577 //
1578 // Account for the bytes consumed
1579 //
1580 pPacket->pBuffer += DataLength;
1581 pPacket->ValidBytes -= DataLength;
1582 DEBUG (( DEBUG_RX,
1583 "0x%08x: Port account for 0x%08x bytes\r\n",
1584 pPort,
1585 DataLength ));
1586
1587 //
1588 // Determine if the entire packet was consumed
1589 //
1590 if (( 0 == pPacket->ValidBytes )
1591 || ( SOCK_STREAM != pPort->pSocket->Type )) {
1592 //
1593 // All done with this packet
1594 // Account for any discarded data
1595 //
1596 *pSkipBytes = pPacket->ValidBytes;
1597 }
1598 else
1599 {
1600 //
1601 // More data to consume later
1602 //
1603 *pbConsumePacket = FALSE;
1604 }
1605 }
1606
1607 //
1608 // Return the data length and the buffer address
1609 //
1610 *pDataLength = DataLength;
1611 DBG_EXIT_HEX ( pBuffer );
1612 return pBuffer;
1613 }
1614
1615
1616 /**
1617 Get the remote socket address.
1618
1619 This routine returns the address of the remote connection point
1620 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1621
1622 This routine is called by ::EslSocketGetPeerAddress to detemine
1623 the TCPv4 address and por number associated with the network adapter.
1624
1625 @param [in] pPort Address of an ::ESL_PORT structure.
1626
1627 @param [out] pAddress Network address to receive the remote system address
1628
1629 **/
1630 VOID
1631 EslTcp4RemoteAddressGet (
1632 IN ESL_PORT * pPort,
1633 OUT struct sockaddr * pAddress
1634 )
1635 {
1636 struct sockaddr_in * pRemoteAddress;
1637 ESL_TCP4_CONTEXT * pTcp4;
1638
1639 DBG_ENTER ( );
1640
1641 //
1642 // Return the remote address
1643 //
1644 pTcp4 = &pPort->Context.Tcp4;
1645 pRemoteAddress = (struct sockaddr_in *)pAddress;
1646 pRemoteAddress->sin_family = AF_INET;
1647 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
1648 CopyMem ( &pRemoteAddress->sin_addr,
1649 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1650 sizeof ( pRemoteAddress->sin_addr ));
1651
1652 DBG_EXIT ( );
1653 }
1654
1655
1656 /**
1657 Set the remote address
1658
1659 This routine sets the remote address in the port.
1660
1661 This routine is called by ::EslSocketConnect to specify the
1662 remote network address.
1663
1664 @param [in] pPort Address of an ::ESL_PORT structure.
1665
1666 @param [in] pSockAddr Network address of the remote system.
1667
1668 @param [in] SockAddrLength Length in bytes of the network address.
1669
1670 @retval EFI_SUCCESS The operation was successful
1671
1672 **/
1673 EFI_STATUS
1674 EslTcp4RemoteAddressSet (
1675 IN ESL_PORT * pPort,
1676 IN CONST struct sockaddr * pSockAddr,
1677 IN socklen_t SockAddrLength
1678 )
1679 {
1680 CONST struct sockaddr_in * pRemoteAddress;
1681 ESL_TCP4_CONTEXT * pTcp4;
1682 EFI_STATUS Status;
1683
1684 DBG_ENTER ( );
1685
1686 //
1687 // Set the remote address
1688 //
1689 pTcp4 = &pPort->Context.Tcp4;
1690 pRemoteAddress = (struct sockaddr_in *)pSockAddr;
1691 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
1692 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
1693 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
1694 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
1695 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
1696 Status = EFI_SUCCESS;
1697 if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {
1698 DEBUG (( DEBUG_CONNECT,
1699 "ERROR - Invalid remote address\r\n" ));
1700 Status = EFI_INVALID_PARAMETER;
1701 pPort->pSocket->errno = EAFNOSUPPORT;
1702 }
1703
1704 //
1705 // Return the operation status
1706 //
1707 DBG_EXIT_STATUS ( Status );
1708 return Status;
1709 }
1710
1711
1712 /**
1713 Process the receive completion
1714
1715 This routine queues the data in FIFO order in either the urgent
1716 or normal data queues depending upon the type of data received.
1717 See the \ref ReceiveEngine section.
1718
1719 This routine is called by the TCPv4 driver when some data is
1720 received.
1721
1722 Buffer the data that was just received.
1723
1724 @param [in] Event The receive completion event
1725
1726 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1727
1728 **/
1729 VOID
1730 EslTcp4RxComplete (
1731 IN EFI_EVENT Event,
1732 IN ESL_IO_MGMT * pIo
1733 )
1734 {
1735 BOOLEAN bUrgent;
1736 size_t LengthInBytes;
1737 ESL_PACKET * pPacket;
1738 EFI_STATUS Status;
1739
1740 DBG_ENTER ( );
1741
1742 //
1743 // Get the operation status.
1744 //
1745 Status = pIo->Token.Tcp4Rx.CompletionToken.Status;
1746
1747 //
1748 // +--------------------+ +---------------------------+
1749 // | ESL_IO_MGMT | | ESL_PACKET |
1750 // | | | |
1751 // | +---------------+ +-----------------------+ |
1752 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1753 // | | RxData --> | | |
1754 // | | | +-----------------------+---+
1755 // | | Event | | Data Buffer |
1756 // +----+---------------+ | |
1757 // | |
1758 // +---------------------------+
1759 //
1760 //
1761 // Duplicate the buffer address and length for use by the
1762 // buffer handling code in EslTcp4Receive. These fields are
1763 // used when a partial read is done of the data from the
1764 // packet.
1765 //
1766 pPacket = pIo->pPacket;
1767 pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
1768 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
1769 pPacket->ValidBytes = LengthInBytes;
1770
1771 //
1772 // Get the data type so that it may be linked to the
1773 // correct receive buffer list on the ESL_SOCKET structure
1774 //
1775 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
1776
1777 //
1778 // Complete this request
1779 //
1780 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
1781 DBG_EXIT ( );
1782 }
1783
1784
1785 /**
1786 Start a receive operation
1787
1788 This routine posts a receive buffer to the TCPv4 driver.
1789 See the \ref ReceiveEngine section.
1790
1791 This support routine is called by EslSocketRxStart.
1792
1793 @param [in] pPort Address of an ::ESL_PORT structure.
1794 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1795
1796 **/
1797 VOID
1798 EslTcp4RxStart (
1799 IN ESL_PORT * pPort,
1800 IN ESL_IO_MGMT * pIo
1801 )
1802 {
1803 ESL_PACKET * pPacket;
1804
1805 DBG_ENTER ( );
1806
1807 //
1808 // Initialize the buffer for receive
1809 //
1810 pPacket = pIo->pPacket;
1811 pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
1812 pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
1813 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
1814 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;
1815 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];
1816
1817 DBG_EXIT ( );
1818 }
1819
1820
1821 /**
1822 Determine if the socket is configured.
1823
1824 This routine uses the flag ESL_SOCKET::bConfigured to determine
1825 if the network layer's configuration routine has been called.
1826
1827 This routine is called by EslSocketIsConfigured to verify
1828 that the socket has been configured.
1829
1830 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1831
1832 @retval EFI_SUCCESS - The port is connected
1833 @retval EFI_NOT_STARTED - The port is not connected
1834
1835 **/
1836 EFI_STATUS
1837 EslTcp4SocketIsConfigured (
1838 IN ESL_SOCKET * pSocket
1839 )
1840 {
1841 EFI_STATUS Status;
1842
1843 DBG_ENTER ( );
1844
1845 //
1846 // Determine the socket configuration status
1847 //
1848 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
1849
1850 //
1851 // Return the port connected state.
1852 //
1853 DBG_EXIT_STATUS ( Status );
1854 return Status;
1855 }
1856
1857
1858 /**
1859 Buffer data for transmission over a network connection.
1860
1861 This routine buffers data for the transmit engine in one of two
1862 queues, one for urgent (out-of-band) data and the other for normal
1863 data. The urgent data is provided to TCP as soon as it is available,
1864 allowing the TCP layer to schedule transmission of the urgent data
1865 between packets of normal data.
1866
1867 This routine is called by ::EslSocketTransmit to buffer
1868 data for transmission. When the \ref TransmitEngine has resources,
1869 this routine will start the transmission of the next buffer on
1870 the network connection.
1871
1872 Transmission errors are returned during the next transmission or
1873 during the close operation. Only buffering errors are returned
1874 during the current transmission attempt.
1875
1876 @param [in] pSocket Address of an ::ESL_SOCKET structure
1877
1878 @param [in] Flags Message control flags
1879
1880 @param [in] BufferLength Length of the the buffer
1881
1882 @param [in] pBuffer Address of a buffer to receive the data.
1883
1884 @param [in] pDataLength Number of received data bytes in the buffer.
1885
1886 @param [in] pAddress Network address of the remote system address
1887
1888 @param [in] AddressLength Length of the remote network address structure
1889
1890 @retval EFI_SUCCESS - Socket data successfully buffered
1891
1892 **/
1893 EFI_STATUS
1894 EslTcp4TxBuffer (
1895 IN ESL_SOCKET * pSocket,
1896 IN int Flags,
1897 IN size_t BufferLength,
1898 IN CONST UINT8 * pBuffer,
1899 OUT size_t * pDataLength,
1900 IN const struct sockaddr * pAddress,
1901 IN socklen_t AddressLength
1902 )
1903 {
1904 BOOLEAN bUrgent;
1905 BOOLEAN bUrgentQueue;
1906 ESL_PACKET * pPacket;
1907 ESL_IO_MGMT ** ppActive;
1908 ESL_IO_MGMT ** ppFree;
1909 ESL_PORT * pPort;
1910 ESL_PACKET ** ppQueueHead;
1911 ESL_PACKET ** ppQueueTail;
1912 ESL_PACKET * pPreviousPacket;
1913 ESL_TCP4_CONTEXT * pTcp4;
1914 size_t * pTxBytes;
1915 EFI_TCP4_TRANSMIT_DATA * pTxData;
1916 EFI_STATUS Status;
1917 EFI_TPL TplPrevious;
1918
1919 DBG_ENTER ( );
1920
1921 //
1922 // Assume failure
1923 //
1924 Status = EFI_UNSUPPORTED;
1925 pSocket->errno = ENOTCONN;
1926 *pDataLength = 0;
1927
1928 //
1929 // Verify that the socket is connected
1930 //
1931 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
1932 //
1933 // Locate the port
1934 //
1935 pPort = pSocket->pPortList;
1936 if ( NULL != pPort ) {
1937 //
1938 // Determine the queue head
1939 //
1940 pTcp4 = &pPort->Context.Tcp4;
1941 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
1942 bUrgentQueue = bUrgent
1943 && ( !pSocket->bOobInLine )
1944 && pSocket->pApi->bOobSupported;
1945 if ( bUrgentQueue ) {
1946 ppQueueHead = &pSocket->pTxOobPacketListHead;
1947 ppQueueTail = &pSocket->pTxOobPacketListTail;
1948 ppActive = &pPort->pTxOobActive;
1949 ppFree = &pPort->pTxOobFree;
1950 pTxBytes = &pSocket->TxOobBytes;
1951 }
1952 else {
1953 ppQueueHead = &pSocket->pTxPacketListHead;
1954 ppQueueTail = &pSocket->pTxPacketListTail;
1955 ppActive = &pPort->pTxActive;
1956 ppFree = &pPort->pTxFree;
1957 pTxBytes = &pSocket->TxBytes;
1958 }
1959
1960 //
1961 // Verify that there is enough room to buffer another
1962 // transmit operation
1963 //
1964 if ( pSocket->MaxTxBuf > *pTxBytes ) {
1965 if ( pPort->bTxFlowControl ) {
1966 DEBUG (( DEBUG_TX,
1967 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
1968 pPort,
1969 pSocket->MaxTxBuf,
1970 *pTxBytes ));
1971 pPort->bTxFlowControl = FALSE;
1972 }
1973
1974 //
1975 // Attempt to allocate the packet
1976 //
1977 Status = EslSocketPacketAllocate ( &pPacket,
1978 sizeof ( pPacket->Op.Tcp4Tx )
1979 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )
1980 + BufferLength,
1981 0,
1982 DEBUG_TX );
1983 if ( !EFI_ERROR ( Status )) {
1984 //
1985 // Initialize the transmit operation
1986 //
1987 pTxData = &pPacket->Op.Tcp4Tx.TxData;
1988 pTxData->Push = TRUE || bUrgent;
1989 pTxData->Urgent = bUrgent;
1990 pTxData->DataLength = (UINT32) BufferLength;
1991 pTxData->FragmentCount = 1;
1992 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
1993 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];
1994
1995 //
1996 // Copy the data into the buffer
1997 //
1998 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],
1999 pBuffer,
2000 BufferLength );
2001
2002 //
2003 // Synchronize with the socket layer
2004 //
2005 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2006
2007 //
2008 // Stop transmission after an error
2009 //
2010 if ( !EFI_ERROR ( pSocket->TxError )) {
2011 //
2012 // Display the request
2013 //
2014 DEBUG (( DEBUG_TX,
2015 "Send %d %s bytes from 0x%08x\r\n",
2016 BufferLength,
2017 bUrgent ? L"urgent" : L"normal",
2018 pBuffer ));
2019
2020 //
2021 // Queue the data for transmission
2022 //
2023 pPacket->pNext = NULL;
2024 pPreviousPacket = *ppQueueTail;
2025 if ( NULL == pPreviousPacket ) {
2026 *ppQueueHead = pPacket;
2027 }
2028 else {
2029 pPreviousPacket->pNext = pPacket;
2030 }
2031 *ppQueueTail = pPacket;
2032 DEBUG (( DEBUG_TX,
2033 "0x%08x: Packet on %s transmit list\r\n",
2034 pPacket,
2035 bUrgentQueue ? L"urgent" : L"normal" ));
2036
2037 //
2038 // Account for the buffered data
2039 //
2040 *pTxBytes += BufferLength;
2041 *pDataLength = BufferLength;
2042
2043 //
2044 // Start the transmit engine if it is idle
2045 //
2046 if ( NULL != *ppFree ) {
2047 EslSocketTxStart ( pPort,
2048 ppQueueHead,
2049 ppQueueTail,
2050 ppActive,
2051 ppFree );
2052 }
2053 }
2054 else {
2055 //
2056 // Previous transmit error
2057 // Stop transmission
2058 //
2059 Status = pSocket->TxError;
2060 pSocket->errno = EIO;
2061
2062 //
2063 // Free the packet
2064 //
2065 EslSocketPacketFree ( pPacket, DEBUG_TX );
2066 }
2067
2068 //
2069 // Release the socket layer synchronization
2070 //
2071 RESTORE_TPL ( TplPrevious );
2072 }
2073 else {
2074 //
2075 // Packet allocation failed
2076 //
2077 pSocket->errno = ENOMEM;
2078 }
2079 }
2080 else {
2081 if ( !pPort->bTxFlowControl ) {
2082 DEBUG (( DEBUG_TX,
2083 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2084 pPort,
2085 pSocket->MaxTxBuf,
2086 *pTxBytes ));
2087 pPort->bTxFlowControl = TRUE;
2088 }
2089 //
2090 // Not enough buffer space available
2091 //
2092 pSocket->errno = EAGAIN;
2093 Status = EFI_NOT_READY;
2094 }
2095 }
2096 }
2097
2098 //
2099 // Return the operation status
2100 //
2101 DBG_EXIT_STATUS ( Status );
2102 return Status;
2103 }
2104
2105
2106 /**
2107 Process the normal data transmit completion
2108
2109 This routine use ::EslSocketTxComplete to perform the transmit
2110 completion processing for normal data.
2111
2112 This routine is called by the TCPv4 network layer when a
2113 normal data transmit request completes.
2114
2115 @param [in] Event The normal transmit completion event
2116
2117 @param [in] pIo The ESL_IO_MGMT structure address
2118
2119 **/
2120 VOID
2121 EslTcp4TxComplete (
2122 IN EFI_EVENT Event,
2123 IN ESL_IO_MGMT * pIo
2124 )
2125 {
2126 UINT32 LengthInBytes;
2127 ESL_PACKET * pPacket;
2128 ESL_PORT * pPort;
2129 ESL_SOCKET * pSocket;
2130 EFI_STATUS Status;
2131
2132 DBG_ENTER ( );
2133
2134 //
2135 // Locate the active transmit packet
2136 //
2137 pPacket = pIo->pPacket;
2138 pPort = pIo->pPort;
2139 pSocket = pPort->pSocket;
2140
2141 //
2142 // Get the transmit length and status
2143 //
2144 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
2145 pSocket->TxBytes -= LengthInBytes;
2146 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
2147
2148 //
2149 // Complete the transmit operation
2150 //
2151 EslSocketTxComplete ( pIo,
2152 LengthInBytes,
2153 Status,
2154 "Normal ",
2155 &pSocket->pTxPacketListHead,
2156 &pSocket->pTxPacketListTail,
2157 &pPort->pTxActive,
2158 &pPort->pTxFree );
2159 DBG_EXIT ( );
2160 }
2161
2162
2163 /**
2164 Process the urgent data transmit completion
2165
2166 This routine use ::EslSocketTxComplete to perform the transmit
2167 completion processing for urgent data.
2168
2169 This routine is called by the TCPv4 network layer when a
2170 urgent data transmit request completes.
2171
2172 @param [in] Event The urgent transmit completion event
2173
2174 @param [in] pIo The ESL_IO_MGMT structure address
2175
2176 **/
2177 VOID
2178 EslTcp4TxOobComplete (
2179 IN EFI_EVENT Event,
2180 IN ESL_IO_MGMT * pIo
2181 )
2182 {
2183 UINT32 LengthInBytes;
2184 ESL_PACKET * pPacket;
2185 ESL_PORT * pPort;
2186 ESL_SOCKET * pSocket;
2187 EFI_STATUS Status;
2188
2189 DBG_ENTER ( );
2190
2191 //
2192 // Locate the active transmit packet
2193 //
2194 pPacket = pIo->pPacket;
2195 pPort = pIo->pPort;
2196 pSocket = pPort->pSocket;
2197
2198 //
2199 // Get the transmit length and status
2200 //
2201 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
2202 pSocket->TxOobBytes -= LengthInBytes;
2203 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
2204
2205 //
2206 // Complete the transmit operation
2207 //
2208 EslSocketTxComplete ( pIo,
2209 LengthInBytes,
2210 Status,
2211 "Urgent ",
2212 &pSocket->pTxOobPacketListHead,
2213 &pSocket->pTxOobPacketListTail,
2214 &pPort->pTxOobActive,
2215 &pPort->pTxOobFree );
2216 DBG_EXIT ( );
2217 }
2218
2219
2220 /**
2221 Interface between the socket layer and the network specific
2222 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2223 over TCPv4.
2224 **/
2225 CONST ESL_PROTOCOL_API cEslTcp4Api = {
2226 "TCPv4",
2227 IPPROTO_TCP,
2228 OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),
2229 OFFSET_OF ( ESL_LAYER, pTcp4List ),
2230 OFFSET_OF ( struct sockaddr_in, sin_zero ),
2231 sizeof ( struct sockaddr_in ),
2232 AF_INET,
2233 sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),
2234 OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
2235 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),
2236 TRUE,
2237 EADDRINUSE,
2238 EslTcp4Accept,
2239 EslTcp4ConnectPoll,
2240 EslTcp4ConnectStart,
2241 EslTcp4SocketIsConfigured,
2242 EslTcp4LocalAddressGet,
2243 EslTcp4LocalAddressSet,
2244 EslTcp4Listen,
2245 NULL, // OptionGet
2246 NULL, // OptionSet
2247 EslTcp4PacketFree,
2248 EslTcp4PortAllocate,
2249 EslTcp4PortClose,
2250 EslTcp4PortCloseOp,
2251 FALSE,
2252 EslTcp4Receive,
2253 EslTcp4RemoteAddressGet,
2254 EslTcp4RemoteAddressSet,
2255 EslTcp4RxComplete,
2256 EslTcp4RxStart,
2257 EslTcp4TxBuffer,
2258 EslTcp4TxComplete,
2259 EslTcp4TxOobComplete
2260 };