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