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