]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Tcp4.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / StdLib / EfiSocketLib / Tcp4.c
1 /** @file
2 Implement the TCP4 driver support for the socket layer.
3
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7
8 \section ConnectionManagement Connection Management
9
10 The ::EslTcp4Listen routine initially places the SOCK_STREAM or
11 SOCK_SEQPACKET socket into a listen state. When a remote machine
12 makes a connection to the socket, the TCPv4 network layer calls
13 ::EslTcp4ListenComplete to complete the connection processing.
14 EslTcp4ListenComplete manages the connections by placing them in
15 FIFO order in a queue to be serviced by the application. When the
16 number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
17 the new connection is closed. Eventually, the application indirectly
18 calls ::EslTcp4Accept to remove the next connection from the queue
19 and get the associated socket.
20
21 **/
22
23 #include "Socket.h"
24
25
26 /**
27 Attempt to connect to a remote TCP port
28
29 This routine starts the connection processing for a SOCK_STREAM
30 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
31 configures the local TCPv4 connection point and then attempts to
32 connect to a remote system. Upon completion, the
33 ::EslTcp4ConnectComplete routine gets called with the connection
34 status.
35
36 This routine is called by ::EslSocketConnect to initiate the TCPv4
37 network specific connect operations. The connection processing is
38 initiated by this routine and finished by ::EslTcp4ConnectComplete.
39 This pair of routines walks through the list of local TCPv4
40 connection points until a connection to the remote system is
41 made.
42
43 @param [in] pSocket Address of an ::ESL_SOCKET structure.
44
45 @retval EFI_SUCCESS The connection was successfully established.
46 @retval EFI_NOT_READY The connection is in progress, call this routine again.
47 @retval Others The connection attempt failed.
48
49 **/
50 EFI_STATUS
51 EslTcp4ConnectStart (
52 IN ESL_SOCKET * pSocket
53 );
54
55
56 /**
57 Process the connection attempt
58
59 A system has initiated a connection attempt with a socket in the
60 listen state. Attempt to complete the connection.
61
62 The TCPv4 layer calls this routine when a connection is made to
63 the socket in the listen state. See the
64 \ref ConnectionManagement section.
65
66 @param [in] Event The listen completion event
67
68 @param [in] pPort Address of an ::ESL_PORT structure.
69
70 **/
71 VOID
72 EslTcp4ListenComplete (
73 IN EFI_EVENT Event,
74 IN ESL_PORT * pPort
75 );
76
77
78 /**
79 Accept a network connection.
80
81 This routine waits for a network connection to the socket and
82 returns the remote network address to the caller if requested.
83
84 This routine is called by ::EslSocketAccept to handle the TCPv4 protocol
85 specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
86 See the \ref ConnectionManagement section.
87
88 @param [in] pSocket Address of an ::ESL_SOCKET structure.
89
90 @param [in] pSockAddr Address of a buffer to receive the remote
91 network address.
92
93 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
94 On output specifies the length of the
95 remote network address.
96
97 @retval EFI_SUCCESS Remote address is available
98 @retval Others Remote address not available
99
100 **/
101 EFI_STATUS
102 EslTcp4Accept (
103 IN ESL_SOCKET * pSocket,
104 IN struct sockaddr * pSockAddr,
105 IN OUT socklen_t * pSockAddrLength
106 )
107 {
108 ESL_PORT * pPort;
109 struct sockaddr_in * pRemoteAddress;
110 ESL_TCP4_CONTEXT * pTcp4;
111 UINT32 RemoteAddress;
112 EFI_STATUS Status;
113
114 DBG_ENTER ( );
115
116 //
117 // Validate the socket length
118 //
119 pRemoteAddress = (struct sockaddr_in *) pSockAddr;
120 if (( NULL == pSockAddrLength )
121 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {
122 //
123 // Invalid socket address
124 //
125 Status = EFI_INVALID_PARAMETER;
126 pSocket->errno = EINVAL;
127 DEBUG (( DEBUG_ACCEPT,
128 "ERROR - Invalid address length\r\n" ));
129 }
130 else {
131 //
132 // Assume success
133 //
134 Status = EFI_SUCCESS;
135
136 //
137 // Locate the address context
138 //
139 pPort = pSocket->pPortList;
140 pTcp4 = &pPort->Context.Tcp4;
141
142 //
143 // Fill-in the remote address structure
144 //
145 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));
146 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );
147 pRemoteAddress->sin_family = AF_INET;
148 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
149 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
150 RemoteAddress <<= 8;
151 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
152 RemoteAddress <<= 8;
153 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
154 RemoteAddress <<= 8;
155 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
156 pRemoteAddress->sin_addr.s_addr = RemoteAddress;
157 }
158
159 //
160 // Return the operation status
161 //
162 DBG_EXIT_STATUS ( Status );
163 return Status;
164 }
165
166
167 /**
168 Process the remote connection completion event.
169
170 This routine handles the completion of a connection attempt. It
171 releases the port (TCPv4 adapter connection) in the case of an
172 error and start a connection attempt on the next port. If the
173 connection attempt was successful then this routine releases all
174 of the other ports.
175
176 This routine is called by the TCPv4 layer when a connect request
177 completes. It sets the ESL_SOCKET::bConnected flag to notify the
178 ::EslTcp4ConnectComplete routine that the connection is available.
179 The flag is set when the connection is established or no more ports
180 exist in the list. The connection status is passed via
181 ESL_SOCKET::ConnectStatus.
182
183 @param [in] Event The connect completion event
184
185 @param [in] pPort Address of an ::ESL_PORT structure.
186
187 **/
188 VOID
189 EslTcp4ConnectComplete (
190 IN EFI_EVENT Event,
191 IN ESL_PORT * pPort
192 )
193 {
194 BOOLEAN bRemoveFirstPort;
195 BOOLEAN bRemovePorts;
196 ESL_PORT * pNextPort;
197 ESL_SOCKET * pSocket;
198 ESL_TCP4_CONTEXT * pTcp4;
199 EFI_STATUS Status;
200
201 DBG_ENTER ( );
202
203 //
204 // Locate the TCP context
205 //
206 pSocket = pPort->pSocket;
207 pTcp4 = &pPort->Context.Tcp4;
208
209 //
210 // Get the connection status
211 //
212 bRemoveFirstPort = FALSE;
213 bRemovePorts = FALSE;
214 Status = pTcp4->ConnectToken.CompletionToken.Status;
215 pSocket->ConnectStatus = Status;
216 if ( !EFI_ERROR ( Status )) {
217 //
218 // The connection was successful
219 //
220 DEBUG (( DEBUG_CONNECT,
221 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
222 pPort,
223 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
224 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
225 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
226 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
227 pTcp4->ConfigData.AccessPoint.RemotePort ));
228
229 //
230 // Start the receive operations
231 //
232 pSocket->bConfigured = TRUE;
233 pSocket->State = SOCKET_STATE_CONNECTED;
234 EslSocketRxStart ( pPort );
235
236 //
237 // Remove the rest of the ports
238 //
239 bRemovePorts = TRUE;
240 }
241 else {
242 //
243 // The connection failed
244 //
245 if ( pPort->bConfigured ) {
246 DEBUG (( DEBUG_CONNECT,
247 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
248 pPort,
249 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
250 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
251 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
252 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
253 pTcp4->ConfigData.AccessPoint.RemotePort,
254 Status ));
255 }
256
257 //
258 // Close the current port
259 //
260 Status = EslSocketPortClose ( pPort );
261 if ( !EFI_ERROR ( Status )) {
262 DEBUG (( DEBUG_CONNECT,
263 "0x%08x: Port closed\r\n",
264 pPort ));
265 }
266 else {
267 DEBUG (( DEBUG_CONNECT,
268 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
269 pPort,
270 Status ));
271 }
272
273 //
274 // Try to connect using the next port
275 //
276 Status = EslTcp4ConnectStart ( pSocket );
277 if ( EFI_NOT_READY != Status ) {
278 bRemoveFirstPort = TRUE;
279 }
280 }
281
282 //
283 // Remove the ports if necessary
284 //
285 if ( bRemoveFirstPort || bRemovePorts ) {
286 //
287 // Remove the first port if necessary
288 //
289 pPort = pSocket->pPortList;
290 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {
291 pPort = pPort->pLinkSocket;
292 }
293
294 //
295 // Remove the rest of the list
296 //
297 while ( NULL != pPort ) {
298 pNextPort = pPort->pLinkSocket;
299 EslSocketPortClose ( pPort );
300 if ( !EFI_ERROR ( Status )) {
301 DEBUG (( DEBUG_CONNECT,
302 "0x%08x: Port closed\r\n",
303 pPort ));
304 }
305 else {
306 DEBUG (( DEBUG_CONNECT,
307 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
308 pPort,
309 Status ));
310 }
311 pPort = pNextPort;
312 }
313
314 //
315 // Notify the poll routine
316 //
317 pSocket->bConnected = TRUE;
318 }
319
320 DBG_EXIT ( );
321 }
322
323
324 /**
325 Poll for completion of the connection attempt.
326
327 This routine polls the ESL_SOCKET::bConnected flag to determine
328 when the connection attempt is complete.
329
330 This routine is called from ::EslSocketConnect to determine when
331 the connection is complete. The ESL_SOCKET::bConnected flag is
332 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
333 a connection or runs out of local network adapters. This routine
334 gets the connection status from ESL_SOCKET::ConnectStatus.
335
336 @param [in] pSocket Address of an ::ESL_SOCKET structure.
337
338 @retval EFI_SUCCESS The connection was successfully established.
339 @retval EFI_NOT_READY The connection is in progress, call this routine again.
340 @retval Others The connection attempt failed.
341
342 **/
343 EFI_STATUS
344 EslTcp4ConnectPoll (
345 IN ESL_SOCKET * pSocket
346 )
347 {
348 EFI_STATUS Status;
349
350 DBG_ENTER ( );
351
352 //
353 // Determine if the connection is complete
354 //
355 if ( !pSocket->bConnected ) {
356 //
357 // Not connected
358 //
359 pSocket->errno = EAGAIN;
360 Status = EFI_NOT_READY;
361 }
362 else {
363 //
364 // The connection processing is complete
365 //
366 pSocket->bConnected = FALSE;
367
368 //
369 // Translate the connection status
370 //
371 Status = pSocket->ConnectStatus;
372 switch ( Status ) {
373 default:
374 case EFI_DEVICE_ERROR:
375 pSocket->errno = EIO;
376 break;
377
378 case EFI_ABORTED:
379 pSocket->errno = ECONNABORTED;
380 break;
381
382 case EFI_ACCESS_DENIED:
383 pSocket->errno = EACCES;
384 break;
385
386 case EFI_CONNECTION_RESET:
387 pSocket->errno = ECONNRESET;
388 break;
389
390 case EFI_INVALID_PARAMETER:
391 pSocket->errno = EADDRNOTAVAIL;
392 break;
393
394 case EFI_HOST_UNREACHABLE:
395 case EFI_NO_RESPONSE:
396 pSocket->errno = EHOSTUNREACH;
397 break;
398
399 case EFI_NO_MAPPING:
400 pSocket->errno = EAFNOSUPPORT;
401 break;
402
403 case EFI_NO_MEDIA:
404 case EFI_NETWORK_UNREACHABLE:
405 pSocket->errno = ENETDOWN;
406 break;
407
408 case EFI_OUT_OF_RESOURCES:
409 pSocket->errno = ENOBUFS;
410 break;
411
412 case EFI_PORT_UNREACHABLE:
413 case EFI_PROTOCOL_UNREACHABLE:
414 case EFI_CONNECTION_REFUSED:
415 pSocket->errno = ECONNREFUSED;
416 break;
417
418 case EFI_SUCCESS:
419 pSocket->errno = 0;
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_PORT * pNewPort;
838 ESL_SOCKET * pNewSocket;
839 ESL_SOCKET * pSocket;
840 ESL_TCP4_CONTEXT * pTcp4;
841 EFI_TCP4_PROTOCOL * pTcp4Protocol;
842 EFI_STATUS Status;
843 EFI_HANDLE TcpPortHandle;
844 EFI_STATUS TempStatus;
845
846 DBG_ENTER ( );
847 VERIFY_AT_TPL ( TPL_SOCKETS );
848
849 //
850 // Assume success
851 //
852 Status = EFI_SUCCESS;
853
854 //
855 // Determine if this connection fits into the connection FIFO
856 //
857 pSocket = pPort->pSocket;
858 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;
859 if (( SOCKET_STATE_LISTENING == pSocket->State )
860 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {
861 //
862 // Allocate a socket for this connection
863 //
864 ChildHandle = NULL;
865 Status = EslSocketAllocate ( &ChildHandle,
866 DEBUG_CONNECTION,
867 &pNewSocket );
868 if ( !EFI_ERROR ( Status )) {
869 //
870 // Clone the socket parameters
871 //
872 pNewSocket->pApi = pSocket->pApi;
873 pNewSocket->Domain = pSocket->Domain;
874 pNewSocket->Protocol = pSocket->Protocol;
875 pNewSocket->Type = pSocket->Type;
876
877 //
878 // Build the local address
879 //
880 pTcp4 = &pPort->Context.Tcp4;
881 LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
882 LocalAddress.sin_family = AF_INET;
883 LocalAddress.sin_port = 0;
884 LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];
885
886 //
887 // Allocate a port for this connection
888 // Note in this instance Configure may not be called with NULL!
889 //
890 Status = EslSocketPortAllocate ( pNewSocket,
891 pPort->pService,
892 TcpPortHandle,
893 (struct sockaddr *)&LocalAddress,
894 FALSE,
895 DEBUG_CONNECTION,
896 &pNewPort );
897 if ( !EFI_ERROR ( Status )) {
898 //
899 // Restart the listen operation on the port
900 //
901 pTcp4Protocol = pPort->pProtocol.TCPv4;
902 Status = pTcp4Protocol->Accept ( pTcp4Protocol,
903 &pTcp4->ListenToken );
904
905 //
906 // Close the TCP port using SocketClose
907 //
908 TcpPortHandle = NULL;
909 pTcp4 = &pNewPort->Context.Tcp4;
910
911 //
912 // Check for an accept call error
913 //
914 if ( !EFI_ERROR ( Status )) {
915 //
916 // Get the port configuration
917 //
918 pNewPort->bConfigured = TRUE;
919 pConfigData = &pTcp4->ConfigData;
920 pConfigData->ControlOption = &pTcp4->Option;
921 pTcp4Protocol = pNewPort->pProtocol.TCPv4;
922 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,
923 NULL,
924 pConfigData,
925 NULL,
926 NULL,
927 NULL );
928 if ( !EFI_ERROR ( Status )) {
929 //
930 // Add the new socket to the connection FIFO
931 //
932 if ( NULL == pSocket->pFifoTail ) {
933 //
934 // First connection
935 //
936 pSocket->pFifoHead = pNewSocket;
937 }
938 else {
939 //
940 // Add to end of list.
941 //
942 pSocket->pFifoTail->pNextConnection = pNewSocket;
943 }
944 pSocket->pFifoTail = pNewSocket;
945 pSocket->FifoDepth += 1;
946
947 //
948 // Update the socket state
949 //
950 pNewSocket->State = SOCKET_STATE_IN_FIFO;
951
952 //
953 // Log the connection
954 //
955 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
956 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
957 pNewSocket,
958 pConfigData->AccessPoint.StationAddress.Addr[0],
959 pConfigData->AccessPoint.StationAddress.Addr[1],
960 pConfigData->AccessPoint.StationAddress.Addr[2],
961 pConfigData->AccessPoint.StationAddress.Addr[3],
962 pConfigData->AccessPoint.StationPort,
963 pConfigData->AccessPoint.RemoteAddress.Addr[0],
964 pConfigData->AccessPoint.RemoteAddress.Addr[1],
965 pConfigData->AccessPoint.RemoteAddress.Addr[2],
966 pConfigData->AccessPoint.RemoteAddress.Addr[3],
967 pConfigData->AccessPoint.RemotePort ));
968 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
969 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
970 pSocket,
971 pNewSocket,
972 pSocket->FifoDepth ));
973
974 //
975 // Start the receive operation
976 //
977 EslSocketRxStart ( pNewPort );
978 }
979 else {
980 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
981 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
982 pNewPort,
983 Status ));
984 }
985 }
986 else {
987 //
988 // The listen failed on this port
989 //
990 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,
991 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
992 pPort,
993 Status ));
994
995 //
996 // Close the listening port
997 //
998 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
999 }
1000 }
1001
1002 //
1003 // Done with the socket if necessary
1004 //
1005 if ( EFI_ERROR ( Status )) {
1006 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,
1007 TRUE,
1008 &pSocket->errno );
1009 ASSERT ( EFI_SUCCESS == TempStatus );
1010 }
1011 }
1012 }
1013 else {
1014 DEBUG (( DEBUG_CONNECTION,
1015 "0x%08x: Socket FIFO full, connection refused\r\n",
1016 pSocket ));
1017
1018 //
1019 // The FIFO is full or the socket is in the wrong state
1020 //
1021 Status = EFI_BUFFER_TOO_SMALL;
1022 }
1023
1024 //
1025 // Close the connection if necessary
1026 //
1027 if (( EFI_ERROR ( Status ))
1028 && ( NULL == TcpPortHandle )) {
1029 //
1030 // TODO: Finish this code path
1031 // The new connection does not fit into the connection FIFO
1032 //
1033 // Process:
1034 // Call close
1035 // Release the resources
1036
1037 }
1038
1039 DBG_EXIT ( );
1040 }
1041
1042
1043 /**
1044 Get the local socket address.
1045
1046 This routine returns the IPv4 address and TCP port number associated
1047 with the local socket.
1048
1049 This routine is called by ::EslSocketGetLocalAddress to determine the
1050 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1051
1052 @param [in] pPort Address of an ::ESL_PORT structure.
1053
1054 @param [out] pSockAddr Network address to receive the local system address
1055
1056 **/
1057 VOID
1058 EslTcp4LocalAddressGet (
1059 IN ESL_PORT * pPort,
1060 OUT struct sockaddr * pSockAddr
1061 )
1062 {
1063 struct sockaddr_in * pLocalAddress;
1064 ESL_TCP4_CONTEXT * pTcp4;
1065
1066 DBG_ENTER ( );
1067
1068 //
1069 // Return the local address
1070 //
1071 pTcp4 = &pPort->Context.Tcp4;
1072 pLocalAddress = (struct sockaddr_in *)pSockAddr;
1073 pLocalAddress->sin_family = AF_INET;
1074 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
1075 CopyMem ( &pLocalAddress->sin_addr,
1076 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
1077 sizeof ( pLocalAddress->sin_addr ));
1078
1079 DBG_EXIT ( );
1080 }
1081
1082
1083 /**
1084 Set the local port address.
1085
1086 This routine sets the local port address.
1087
1088 This support routine is called by ::EslSocketPortAllocate.
1089
1090 @param [in] pPort Address of an ESL_PORT structure
1091 @param [in] pSockAddr Address of a sockaddr structure that contains the
1092 connection point on the local machine. An IPv4 address
1093 of INADDR_ANY specifies that the connection is made to
1094 all of the network stacks on the platform. Specifying a
1095 specific IPv4 address restricts the connection to the
1096 network stack supporting that address. Specifying zero
1097 for the port causes the network layer to assign a port
1098 number from the dynamic range. Specifying a specific
1099 port number causes the network layer to use that port.
1100
1101 @param [in] bBindTest TRUE = run bind testing
1102
1103 @retval EFI_SUCCESS The operation was successful
1104
1105 **/
1106 EFI_STATUS
1107 EslTcp4LocalAddressSet (
1108 IN ESL_PORT * pPort,
1109 IN CONST struct sockaddr * pSockAddr,
1110 IN BOOLEAN bBindTest
1111 )
1112 {
1113 EFI_TCP4_ACCESS_POINT * pAccessPoint;
1114 CONST struct sockaddr_in * pIpAddress;
1115 CONST UINT8 * pIpv4Address;
1116 EFI_STATUS Status;
1117
1118 DBG_ENTER ( );
1119
1120 //
1121 // Validate the address
1122 //
1123 pIpAddress = (struct sockaddr_in *)pSockAddr;
1124 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
1125 //
1126 // The local address must not be the broadcast address
1127 //
1128 Status = EFI_INVALID_PARAMETER;
1129 pPort->pSocket->errno = EADDRNOTAVAIL;
1130 }
1131 else {
1132 //
1133 // Set the local address
1134 //
1135 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
1136 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
1137 pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];
1138 pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];
1139 pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];
1140 pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];
1141
1142 //
1143 // Determine if the default address is used
1144 //
1145 pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
1146
1147 //
1148 // Set the subnet mask
1149 //
1150 if ( pAccessPoint->UseDefaultAddress ) {
1151 pAccessPoint->SubnetMask.Addr[0] = 0;
1152 pAccessPoint->SubnetMask.Addr[1] = 0;
1153 pAccessPoint->SubnetMask.Addr[2] = 0;
1154 pAccessPoint->SubnetMask.Addr[3] = 0;
1155 }
1156 else {
1157 pAccessPoint->SubnetMask.Addr[0] = 0xff;
1158 pAccessPoint->SubnetMask.Addr[1] = ( 128 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;
1159 pAccessPoint->SubnetMask.Addr[2] = ( 192 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;
1160 pAccessPoint->SubnetMask.Addr[3] = ( 224 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;
1161 }
1162
1163 //
1164 // Validate the IP address
1165 //
1166 pAccessPoint->StationPort = 0;
1167 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
1168 : EFI_SUCCESS;
1169 if ( !EFI_ERROR ( Status )) {
1170 //
1171 // Set the port number
1172 //
1173 pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );
1174 pPort->pSocket->bAddressSet = TRUE;
1175
1176 //
1177 // Display the local address
1178 //
1179 DEBUG (( DEBUG_BIND,
1180 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1181 pPort,
1182 pAccessPoint->StationAddress.Addr[0],
1183 pAccessPoint->StationAddress.Addr[1],
1184 pAccessPoint->StationAddress.Addr[2],
1185 pAccessPoint->StationAddress.Addr[3],
1186 pAccessPoint->StationPort ));
1187 }
1188 }
1189
1190 //
1191 // Return the operation status
1192 //
1193 DBG_EXIT_STATUS ( Status );
1194 return Status;
1195 }
1196
1197
1198 /**
1199 Free a receive packet
1200
1201 This routine performs the network specific operations necessary
1202 to free a receive packet.
1203
1204 This routine is called by ::EslSocketPortCloseTxDone to free a
1205 receive packet.
1206
1207 @param [in] pPacket Address of an ::ESL_PACKET structure.
1208 @param [in, out] pRxBytes Address of the count of RX bytes
1209
1210 **/
1211 VOID
1212 EslTcp4PacketFree (
1213 IN ESL_PACKET * pPacket,
1214 IN OUT size_t * pRxBytes
1215 )
1216 {
1217 DBG_ENTER ( );
1218
1219 //
1220 // Account for the receive bytes
1221 //
1222 *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;
1223 DBG_EXIT ( );
1224 }
1225
1226
1227 /**
1228 Initialize the network specific portions of an ::ESL_PORT structure.
1229
1230 This routine initializes the network specific portions of an
1231 ::ESL_PORT structure for use by the socket.
1232
1233 This support routine is called by ::EslSocketPortAllocate
1234 to connect the socket with the underlying network adapter
1235 running the TCPv4 protocol.
1236
1237 @param [in] pPort Address of an ESL_PORT structure
1238 @param [in] DebugFlags Flags for debug messages
1239
1240 @retval EFI_SUCCESS - Socket successfully created
1241
1242 **/
1243 EFI_STATUS
1244 EslTcp4PortAllocate (
1245 IN ESL_PORT * pPort,
1246 IN UINTN DebugFlags
1247 )
1248 {
1249 EFI_TCP4_ACCESS_POINT * pAccessPoint;
1250 ESL_SOCKET * pSocket;
1251 ESL_TCP4_CONTEXT * pTcp4;
1252 EFI_STATUS Status;
1253
1254 DBG_ENTER ( );
1255
1256 //
1257 // Use for/break instead of goto
1258 for ( ; ; ) {
1259 //
1260 // Allocate the close event
1261 //
1262 pSocket = pPort->pSocket;
1263 pTcp4 = &pPort->Context.Tcp4;
1264 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1265 TPL_SOCKETS,
1266 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
1267 pPort,
1268 &pTcp4->CloseToken.CompletionToken.Event);
1269 if ( EFI_ERROR ( Status )) {
1270 DEBUG (( DEBUG_ERROR | DebugFlags,
1271 "ERROR - Failed to create the close event, Status: %r\r\n",
1272 Status ));
1273 pSocket->errno = ENOMEM;
1274 break;
1275 }
1276 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1277 "0x%08x: Created close event\r\n",
1278 pTcp4->CloseToken.CompletionToken.Event ));
1279
1280 //
1281 // Allocate the connection event
1282 //
1283 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1284 TPL_SOCKETS,
1285 (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,
1286 pPort,
1287 &pTcp4->ConnectToken.CompletionToken.Event);
1288 if ( EFI_ERROR ( Status )) {
1289 DEBUG (( DEBUG_ERROR | DebugFlags,
1290 "ERROR - Failed to create the connect event, Status: %r\r\n",
1291 Status ));
1292 pSocket->errno = ENOMEM;
1293 break;
1294 }
1295 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1296 "0x%08x: Created connect event\r\n",
1297 pTcp4->ConnectToken.CompletionToken.Event ));
1298
1299 //
1300 // Initialize the port
1301 //
1302 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );
1303 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );
1304 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );
1305
1306 //
1307 // Save the cancel, receive and transmit addresses
1308 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1309 //
1310 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;
1311 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;
1312 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;
1313 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;
1314
1315 //
1316 // Set the configuration flags
1317 //
1318 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
1319 pAccessPoint->ActiveFlag = FALSE;
1320 pTcp4->ConfigData.TimeToLive = 255;
1321 break;
1322 }
1323
1324 //
1325 // Return the operation status
1326 //
1327 DBG_EXIT_STATUS ( Status );
1328 return Status;
1329 }
1330
1331
1332 /**
1333 Close a TCP4 port.
1334
1335 This routine releases the network specific resources allocated by
1336 ::EslTcp4PortAllocate.
1337
1338 This routine is called by ::EslSocketPortClose.
1339 See the \ref PortCloseStateMachine section.
1340
1341 @param [in] pPort Address of an ::ESL_PORT structure.
1342
1343 @retval EFI_SUCCESS The port is closed
1344 @retval other Port close error
1345
1346 **/
1347 EFI_STATUS
1348 EslTcp4PortClose (
1349 IN ESL_PORT * pPort
1350 )
1351 {
1352 UINTN DebugFlags;
1353 ESL_TCP4_CONTEXT * pTcp4;
1354 EFI_STATUS Status;
1355
1356 DBG_ENTER ( );
1357
1358 //
1359 // Locate the port in the socket list
1360 //
1361 Status = EFI_SUCCESS;
1362 DebugFlags = pPort->DebugFlags;
1363 pTcp4 = &pPort->Context.Tcp4;
1364
1365 //
1366 // Done with the connect event
1367 //
1368 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {
1369 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );
1370 if ( !EFI_ERROR ( Status )) {
1371 DEBUG (( DebugFlags | DEBUG_POOL,
1372 "0x%08x: Closed connect event\r\n",
1373 pTcp4->ConnectToken.CompletionToken.Event ));
1374 }
1375 else {
1376 DEBUG (( DEBUG_ERROR | DebugFlags,
1377 "ERROR - Failed to close the connect event, Status: %r\r\n",
1378 Status ));
1379 ASSERT ( EFI_SUCCESS == Status );
1380 }
1381 }
1382
1383 //
1384 // Done with the close event
1385 //
1386 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {
1387 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );
1388 if ( !EFI_ERROR ( Status )) {
1389 DEBUG (( DebugFlags | DEBUG_POOL,
1390 "0x%08x: Closed close event\r\n",
1391 pTcp4->CloseToken.CompletionToken.Event ));
1392 }
1393 else {
1394 DEBUG (( DEBUG_ERROR | DebugFlags,
1395 "ERROR - Failed to close the close event, Status: %r\r\n",
1396 Status ));
1397 ASSERT ( EFI_SUCCESS == Status );
1398 }
1399 }
1400
1401 //
1402 // Done with the listen completion event
1403 //
1404 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {
1405 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );
1406 if ( !EFI_ERROR ( Status )) {
1407 DEBUG (( DebugFlags | DEBUG_POOL,
1408 "0x%08x: Closed listen completion event\r\n",
1409 pTcp4->ListenToken.CompletionToken.Event ));
1410 }
1411 else {
1412 DEBUG (( DEBUG_ERROR | DebugFlags,
1413 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1414 Status ));
1415 ASSERT ( EFI_SUCCESS == Status );
1416 }
1417 }
1418
1419 //
1420 // Return the operation status
1421 //
1422 DBG_EXIT_STATUS ( Status );
1423 return Status;
1424 }
1425
1426
1427 /**
1428 Perform the network specific close operation on the port.
1429
1430 This routine performs a cancel operations on the TCPv4 port to
1431 shutdown the receive operations on the port.
1432
1433 This routine is called by the ::EslSocketPortCloseTxDone
1434 routine after the port completes all of the transmission.
1435
1436 @param [in] pPort Address of an ::ESL_PORT structure.
1437
1438 @retval EFI_SUCCESS The port is closed, not normally returned
1439 @retval EFI_NOT_READY The port is still closing
1440 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1441 most likely the routine was called already.
1442
1443 **/
1444 EFI_STATUS
1445 EslTcp4PortCloseOp (
1446 IN ESL_PORT * pPort
1447 )
1448 {
1449 ESL_TCP4_CONTEXT * pTcp4;
1450 EFI_TCP4_PROTOCOL * pTcp4Protocol;
1451 EFI_STATUS Status;
1452
1453 DBG_ENTER ( );
1454
1455 //
1456 // Close the configured port
1457 //
1458 Status = EFI_SUCCESS;
1459 pTcp4 = &pPort->Context.Tcp4;
1460 pTcp4Protocol = pPort->pProtocol.TCPv4;
1461 pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;
1462 Status = pTcp4Protocol->Close ( pTcp4Protocol,
1463 &pTcp4->CloseToken );
1464 if ( !EFI_ERROR ( Status )) {
1465 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
1466 "0x%08x: Port close started\r\n",
1467 pPort ));
1468 }
1469 else {
1470 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
1471 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1472 pPort,
1473 Status ));
1474 }
1475
1476 //
1477 // Return the operation status
1478 //
1479 DBG_EXIT_STATUS ( Status );
1480 return Status;
1481 }
1482
1483
1484 /**
1485 Receive data from a network connection.
1486
1487 This routine attempts to return buffered data to the caller. The
1488 data is removed from the urgent queue if the message flag MSG_OOB
1489 is specified, otherwise data is removed from the normal queue.
1490 See the \ref ReceiveEngine section.
1491
1492 This routine is called by ::EslSocketReceive to handle the network
1493 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1494 sockets.
1495
1496 @param [in] pPort Address of an ::ESL_PORT structure.
1497
1498 @param [in] pPacket Address of an ::ESL_PACKET structure.
1499
1500 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1501
1502 @param [in] BufferLength Length of the the buffer
1503
1504 @param [in] pBuffer Address of a buffer to receive the data.
1505
1506 @param [in] pDataLength Number of received data bytes in the buffer.
1507
1508 @param [out] pAddress Network address to receive the remote system address
1509
1510 @param [out] pSkipBytes Address to receive the number of bytes skipped
1511
1512 @return Returns the address of the next free byte in the buffer.
1513
1514 **/
1515 UINT8 *
1516 EslTcp4Receive (
1517 IN ESL_PORT * pPort,
1518 IN ESL_PACKET * pPacket,
1519 IN BOOLEAN * pbConsumePacket,
1520 IN size_t BufferLength,
1521 IN UINT8 * pBuffer,
1522 OUT size_t * pDataLength,
1523 OUT struct sockaddr * pAddress,
1524 OUT size_t * pSkipBytes
1525 )
1526 {
1527 size_t DataLength;
1528 struct sockaddr_in * pRemoteAddress;
1529 ESL_TCP4_CONTEXT * pTcp4;
1530
1531 DBG_ENTER ( );
1532
1533 //
1534 // Return the remote system address if requested
1535 //
1536 if ( NULL != pAddress ) {
1537 //
1538 // Build the remote address
1539 //
1540 pTcp4 = &pPort->Context.Tcp4;
1541 DEBUG (( DEBUG_RX,
1542 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1543 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1544 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
1545 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
1546 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
1547 pTcp4->ConfigData.AccessPoint.RemotePort ));
1548 pRemoteAddress = (struct sockaddr_in *)pAddress;
1549 CopyMem ( &pRemoteAddress->sin_addr,
1550 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1551 sizeof ( pRemoteAddress->sin_addr ));
1552 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
1553 }
1554
1555 //
1556 // Determine the amount of received data
1557 //
1558 DataLength = pPacket->ValidBytes;
1559 if ( BufferLength < DataLength ) {
1560 DataLength = BufferLength;
1561 }
1562
1563 //
1564 // Move the data into the buffer
1565 //
1566 DEBUG (( DEBUG_RX,
1567 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1568 pPort,
1569 pPacket,
1570 pBuffer,
1571 DataLength ));
1572 CopyMem ( pBuffer, pPacket->pBuffer, DataLength );
1573
1574 //
1575 // Set the next buffer address
1576 //
1577 pBuffer += DataLength;
1578
1579 //
1580 // Determine if the data is being read
1581 //
1582 if ( *pbConsumePacket ) {
1583 //
1584 // Account for the bytes consumed
1585 //
1586 pPacket->pBuffer += DataLength;
1587 pPacket->ValidBytes -= DataLength;
1588 DEBUG (( DEBUG_RX,
1589 "0x%08x: Port account for 0x%08x bytes\r\n",
1590 pPort,
1591 DataLength ));
1592
1593 //
1594 // Determine if the entire packet was consumed
1595 //
1596 if (( 0 == pPacket->ValidBytes )
1597 || ( SOCK_STREAM != pPort->pSocket->Type )) {
1598 //
1599 // All done with this packet
1600 // Account for any discarded data
1601 //
1602 *pSkipBytes = pPacket->ValidBytes;
1603 }
1604 else
1605 {
1606 //
1607 // More data to consume later
1608 //
1609 *pbConsumePacket = FALSE;
1610 }
1611 }
1612
1613 //
1614 // Return the data length and the buffer address
1615 //
1616 *pDataLength = DataLength;
1617 DBG_EXIT_HEX ( pBuffer );
1618 return pBuffer;
1619 }
1620
1621
1622 /**
1623 Get the remote socket address.
1624
1625 This routine returns the address of the remote connection point
1626 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1627
1628 This routine is called by ::EslSocketGetPeerAddress to detemine
1629 the TCPv4 address and por number associated with the network adapter.
1630
1631 @param [in] pPort Address of an ::ESL_PORT structure.
1632
1633 @param [out] pAddress Network address to receive the remote system address
1634
1635 **/
1636 VOID
1637 EslTcp4RemoteAddressGet (
1638 IN ESL_PORT * pPort,
1639 OUT struct sockaddr * pAddress
1640 )
1641 {
1642 struct sockaddr_in * pRemoteAddress;
1643 ESL_TCP4_CONTEXT * pTcp4;
1644
1645 DBG_ENTER ( );
1646
1647 //
1648 // Return the remote address
1649 //
1650 pTcp4 = &pPort->Context.Tcp4;
1651 pRemoteAddress = (struct sockaddr_in *)pAddress;
1652 pRemoteAddress->sin_family = AF_INET;
1653 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
1654 CopyMem ( &pRemoteAddress->sin_addr,
1655 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
1656 sizeof ( pRemoteAddress->sin_addr ));
1657
1658 DBG_EXIT ( );
1659 }
1660
1661
1662 /**
1663 Set the remote address
1664
1665 This routine sets the remote address in the port.
1666
1667 This routine is called by ::EslSocketConnect to specify the
1668 remote network address.
1669
1670 @param [in] pPort Address of an ::ESL_PORT structure.
1671
1672 @param [in] pSockAddr Network address of the remote system.
1673
1674 @param [in] SockAddrLength Length in bytes of the network address.
1675
1676 @retval EFI_SUCCESS The operation was successful
1677
1678 **/
1679 EFI_STATUS
1680 EslTcp4RemoteAddressSet (
1681 IN ESL_PORT * pPort,
1682 IN CONST struct sockaddr * pSockAddr,
1683 IN socklen_t SockAddrLength
1684 )
1685 {
1686 CONST struct sockaddr_in * pRemoteAddress;
1687 ESL_TCP4_CONTEXT * pTcp4;
1688 EFI_STATUS Status;
1689
1690 DBG_ENTER ( );
1691
1692 //
1693 // Set the remote address
1694 //
1695 pTcp4 = &pPort->Context.Tcp4;
1696 pRemoteAddress = (struct sockaddr_in *)pSockAddr;
1697 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
1698 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
1699 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
1700 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
1701 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
1702 Status = EFI_SUCCESS;
1703 if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {
1704 DEBUG (( DEBUG_CONNECT,
1705 "ERROR - Invalid remote address\r\n" ));
1706 Status = EFI_INVALID_PARAMETER;
1707 pPort->pSocket->errno = EAFNOSUPPORT;
1708 }
1709
1710 //
1711 // Return the operation status
1712 //
1713 DBG_EXIT_STATUS ( Status );
1714 return Status;
1715 }
1716
1717
1718 /**
1719 Process the receive completion
1720
1721 This routine queues the data in FIFO order in either the urgent
1722 or normal data queues depending upon the type of data received.
1723 See the \ref ReceiveEngine section.
1724
1725 This routine is called by the TCPv4 driver when some data is
1726 received.
1727
1728 Buffer the data that was just received.
1729
1730 @param [in] Event The receive completion event
1731
1732 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1733
1734 **/
1735 VOID
1736 EslTcp4RxComplete (
1737 IN EFI_EVENT Event,
1738 IN ESL_IO_MGMT * pIo
1739 )
1740 {
1741 BOOLEAN bUrgent;
1742 size_t LengthInBytes;
1743 ESL_PACKET * pPacket;
1744 EFI_STATUS Status;
1745
1746 DBG_ENTER ( );
1747
1748 //
1749 // Get the operation status.
1750 //
1751 Status = pIo->Token.Tcp4Rx.CompletionToken.Status;
1752
1753 //
1754 // +--------------------+ +---------------------------+
1755 // | ESL_IO_MGMT | | ESL_PACKET |
1756 // | | | |
1757 // | +---------------+ +-----------------------+ |
1758 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1759 // | | RxData --> | | |
1760 // | | | +-----------------------+---+
1761 // | | Event | | Data Buffer |
1762 // +----+---------------+ | |
1763 // | |
1764 // +---------------------------+
1765 //
1766 //
1767 // Duplicate the buffer address and length for use by the
1768 // buffer handling code in EslTcp4Receive. These fields are
1769 // used when a partial read is done of the data from the
1770 // packet.
1771 //
1772 pPacket = pIo->pPacket;
1773 pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
1774 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
1775 pPacket->ValidBytes = LengthInBytes;
1776
1777 //
1778 // Get the data type so that it may be linked to the
1779 // correct receive buffer list on the ESL_SOCKET structure
1780 //
1781 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
1782
1783 //
1784 // Complete this request
1785 //
1786 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
1787 DBG_EXIT ( );
1788 }
1789
1790
1791 /**
1792 Start a receive operation
1793
1794 This routine posts a receive buffer to the TCPv4 driver.
1795 See the \ref ReceiveEngine section.
1796
1797 This support routine is called by EslSocketRxStart.
1798
1799 @param [in] pPort Address of an ::ESL_PORT structure.
1800 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1801
1802 **/
1803 VOID
1804 EslTcp4RxStart (
1805 IN ESL_PORT * pPort,
1806 IN ESL_IO_MGMT * pIo
1807 )
1808 {
1809 ESL_PACKET * pPacket;
1810
1811 DBG_ENTER ( );
1812
1813 //
1814 // Initialize the buffer for receive
1815 //
1816 pPacket = pIo->pPacket;
1817 pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
1818 pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
1819 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
1820 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;
1821 pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];
1822
1823 DBG_EXIT ( );
1824 }
1825
1826
1827 /**
1828 Determine if the socket is configured.
1829
1830 This routine uses the flag ESL_SOCKET::bConfigured to determine
1831 if the network layer's configuration routine has been called.
1832
1833 This routine is called by EslSocketIsConfigured to verify
1834 that the socket has been configured.
1835
1836 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1837
1838 @retval EFI_SUCCESS - The port is connected
1839 @retval EFI_NOT_STARTED - The port is not connected
1840
1841 **/
1842 EFI_STATUS
1843 EslTcp4SocketIsConfigured (
1844 IN ESL_SOCKET * pSocket
1845 )
1846 {
1847 EFI_STATUS Status;
1848
1849 DBG_ENTER ( );
1850
1851 //
1852 // Determine the socket configuration status
1853 //
1854 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
1855
1856 //
1857 // Return the port connected state.
1858 //
1859 DBG_EXIT_STATUS ( Status );
1860 return Status;
1861 }
1862
1863
1864 /**
1865 Buffer data for transmission over a network connection.
1866
1867 This routine buffers data for the transmit engine in one of two
1868 queues, one for urgent (out-of-band) data and the other for normal
1869 data. The urgent data is provided to TCP as soon as it is available,
1870 allowing the TCP layer to schedule transmission of the urgent data
1871 between packets of normal data.
1872
1873 This routine is called by ::EslSocketTransmit to buffer
1874 data for transmission. When the \ref TransmitEngine has resources,
1875 this routine will start the transmission of the next buffer on
1876 the network connection.
1877
1878 Transmission errors are returned during the next transmission or
1879 during the close operation. Only buffering errors are returned
1880 during the current transmission attempt.
1881
1882 @param [in] pSocket Address of an ::ESL_SOCKET structure
1883
1884 @param [in] Flags Message control flags
1885
1886 @param [in] BufferLength Length of the the buffer
1887
1888 @param [in] pBuffer Address of a buffer to receive the data.
1889
1890 @param [in] pDataLength Number of received data bytes in the buffer.
1891
1892 @param [in] pAddress Network address of the remote system address
1893
1894 @param [in] AddressLength Length of the remote network address structure
1895
1896 @retval EFI_SUCCESS - Socket data successfully buffered
1897
1898 **/
1899 EFI_STATUS
1900 EslTcp4TxBuffer (
1901 IN ESL_SOCKET * pSocket,
1902 IN int Flags,
1903 IN size_t BufferLength,
1904 IN CONST UINT8 * pBuffer,
1905 OUT size_t * pDataLength,
1906 IN const struct sockaddr * pAddress,
1907 IN socklen_t AddressLength
1908 )
1909 {
1910 BOOLEAN bUrgent;
1911 BOOLEAN bUrgentQueue;
1912 ESL_PACKET * pPacket;
1913 ESL_IO_MGMT ** ppActive;
1914 ESL_IO_MGMT ** ppFree;
1915 ESL_PORT * pPort;
1916 ESL_PACKET ** ppQueueHead;
1917 ESL_PACKET ** ppQueueTail;
1918 ESL_PACKET * pPreviousPacket;
1919 size_t * pTxBytes;
1920 EFI_TCP4_TRANSMIT_DATA * pTxData;
1921 EFI_STATUS Status;
1922 EFI_TPL TplPrevious;
1923
1924 DBG_ENTER ( );
1925
1926 //
1927 // Assume failure
1928 //
1929 Status = EFI_UNSUPPORTED;
1930 pSocket->errno = ENOTCONN;
1931 *pDataLength = 0;
1932
1933 //
1934 // Verify that the socket is connected
1935 //
1936 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
1937 //
1938 // Locate the port
1939 //
1940 pPort = pSocket->pPortList;
1941 if ( NULL != pPort ) {
1942 //
1943 // Determine the queue head
1944 //
1945 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
1946 bUrgentQueue = bUrgent
1947 && ( !pSocket->bOobInLine )
1948 && pSocket->pApi->bOobSupported;
1949 if ( bUrgentQueue ) {
1950 ppQueueHead = &pSocket->pTxOobPacketListHead;
1951 ppQueueTail = &pSocket->pTxOobPacketListTail;
1952 ppActive = &pPort->pTxOobActive;
1953 ppFree = &pPort->pTxOobFree;
1954 pTxBytes = &pSocket->TxOobBytes;
1955 }
1956 else {
1957 ppQueueHead = &pSocket->pTxPacketListHead;
1958 ppQueueTail = &pSocket->pTxPacketListTail;
1959 ppActive = &pPort->pTxActive;
1960 ppFree = &pPort->pTxFree;
1961 pTxBytes = &pSocket->TxBytes;
1962 }
1963
1964 //
1965 // Verify that there is enough room to buffer another
1966 // transmit operation
1967 //
1968 if ( pSocket->MaxTxBuf > *pTxBytes ) {
1969 if ( pPort->bTxFlowControl ) {
1970 DEBUG (( DEBUG_TX,
1971 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
1972 pPort,
1973 pSocket->MaxTxBuf,
1974 *pTxBytes ));
1975 pPort->bTxFlowControl = FALSE;
1976 }
1977
1978 //
1979 // Attempt to allocate the packet
1980 //
1981 Status = EslSocketPacketAllocate ( &pPacket,
1982 sizeof ( pPacket->Op.Tcp4Tx )
1983 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )
1984 + BufferLength,
1985 0,
1986 DEBUG_TX );
1987 if ( !EFI_ERROR ( Status )) {
1988 //
1989 // Initialize the transmit operation
1990 //
1991 pTxData = &pPacket->Op.Tcp4Tx.TxData;
1992 pTxData->Push = TRUE || bUrgent;
1993 pTxData->Urgent = bUrgent;
1994 pTxData->DataLength = (UINT32) BufferLength;
1995 pTxData->FragmentCount = 1;
1996 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
1997 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];
1998
1999 //
2000 // Copy the data into the buffer
2001 //
2002 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],
2003 pBuffer,
2004 BufferLength );
2005
2006 //
2007 // Synchronize with the socket layer
2008 //
2009 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
2010
2011 //
2012 // Stop transmission after an error
2013 //
2014 if ( !EFI_ERROR ( pSocket->TxError )) {
2015 //
2016 // Display the request
2017 //
2018 DEBUG (( DEBUG_TX,
2019 "Send %d %s bytes from 0x%08x\r\n",
2020 BufferLength,
2021 bUrgent ? L"urgent" : L"normal",
2022 pBuffer ));
2023
2024 //
2025 // Queue the data for transmission
2026 //
2027 pPacket->pNext = NULL;
2028 pPreviousPacket = *ppQueueTail;
2029 if ( NULL == pPreviousPacket ) {
2030 *ppQueueHead = pPacket;
2031 }
2032 else {
2033 pPreviousPacket->pNext = pPacket;
2034 }
2035 *ppQueueTail = pPacket;
2036 DEBUG (( DEBUG_TX,
2037 "0x%08x: Packet on %s transmit list\r\n",
2038 pPacket,
2039 bUrgentQueue ? L"urgent" : L"normal" ));
2040
2041 //
2042 // Account for the buffered data
2043 //
2044 *pTxBytes += BufferLength;
2045 *pDataLength = BufferLength;
2046
2047 //
2048 // Start the transmit engine if it is idle
2049 //
2050 if ( NULL != *ppFree ) {
2051 EslSocketTxStart ( pPort,
2052 ppQueueHead,
2053 ppQueueTail,
2054 ppActive,
2055 ppFree );
2056 }
2057 }
2058 else {
2059 //
2060 // Previous transmit error
2061 // Stop transmission
2062 //
2063 Status = pSocket->TxError;
2064 pSocket->errno = EIO;
2065
2066 //
2067 // Free the packet
2068 //
2069 EslSocketPacketFree ( pPacket, DEBUG_TX );
2070 }
2071
2072 //
2073 // Release the socket layer synchronization
2074 //
2075 RESTORE_TPL ( TplPrevious );
2076 }
2077 else {
2078 //
2079 // Packet allocation failed
2080 //
2081 pSocket->errno = ENOMEM;
2082 }
2083 }
2084 else {
2085 if ( !pPort->bTxFlowControl ) {
2086 DEBUG (( DEBUG_TX,
2087 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2088 pPort,
2089 pSocket->MaxTxBuf,
2090 *pTxBytes ));
2091 pPort->bTxFlowControl = TRUE;
2092 }
2093 //
2094 // Not enough buffer space available
2095 //
2096 pSocket->errno = EAGAIN;
2097 Status = EFI_NOT_READY;
2098 }
2099 }
2100 }
2101
2102 //
2103 // Return the operation status
2104 //
2105 DBG_EXIT_STATUS ( Status );
2106 return Status;
2107 }
2108
2109
2110 /**
2111 Process the normal data transmit completion
2112
2113 This routine use ::EslSocketTxComplete to perform the transmit
2114 completion processing for normal data.
2115
2116 This routine is called by the TCPv4 network layer when a
2117 normal data transmit request completes.
2118
2119 @param [in] Event The normal transmit completion event
2120
2121 @param [in] pIo The ESL_IO_MGMT structure address
2122
2123 **/
2124 VOID
2125 EslTcp4TxComplete (
2126 IN EFI_EVENT Event,
2127 IN ESL_IO_MGMT * pIo
2128 )
2129 {
2130 UINT32 LengthInBytes;
2131 ESL_PACKET * pPacket;
2132 ESL_PORT * pPort;
2133 ESL_SOCKET * pSocket;
2134 EFI_STATUS Status;
2135
2136 DBG_ENTER ( );
2137
2138 //
2139 // Locate the active transmit packet
2140 //
2141 pPacket = pIo->pPacket;
2142 pPort = pIo->pPort;
2143 pSocket = pPort->pSocket;
2144
2145 //
2146 // Get the transmit length and status
2147 //
2148 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
2149 pSocket->TxBytes -= LengthInBytes;
2150 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
2151
2152 //
2153 // Complete the transmit operation
2154 //
2155 EslSocketTxComplete ( pIo,
2156 LengthInBytes,
2157 Status,
2158 "Normal ",
2159 &pSocket->pTxPacketListHead,
2160 &pSocket->pTxPacketListTail,
2161 &pPort->pTxActive,
2162 &pPort->pTxFree );
2163 DBG_EXIT ( );
2164 }
2165
2166
2167 /**
2168 Process the urgent data transmit completion
2169
2170 This routine use ::EslSocketTxComplete to perform the transmit
2171 completion processing for urgent data.
2172
2173 This routine is called by the TCPv4 network layer when a
2174 urgent data transmit request completes.
2175
2176 @param [in] Event The urgent transmit completion event
2177
2178 @param [in] pIo The ESL_IO_MGMT structure address
2179
2180 **/
2181 VOID
2182 EslTcp4TxOobComplete (
2183 IN EFI_EVENT Event,
2184 IN ESL_IO_MGMT * pIo
2185 )
2186 {
2187 UINT32 LengthInBytes;
2188 ESL_PACKET * pPacket;
2189 ESL_PORT * pPort;
2190 ESL_SOCKET * pSocket;
2191 EFI_STATUS Status;
2192
2193 DBG_ENTER ( );
2194
2195 //
2196 // Locate the active transmit packet
2197 //
2198 pPacket = pIo->pPacket;
2199 pPort = pIo->pPort;
2200 pSocket = pPort->pSocket;
2201
2202 //
2203 // Get the transmit length and status
2204 //
2205 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
2206 pSocket->TxOobBytes -= LengthInBytes;
2207 Status = pIo->Token.Tcp4Tx.CompletionToken.Status;
2208
2209 //
2210 // Complete the transmit operation
2211 //
2212 EslSocketTxComplete ( pIo,
2213 LengthInBytes,
2214 Status,
2215 "Urgent ",
2216 &pSocket->pTxOobPacketListHead,
2217 &pSocket->pTxOobPacketListTail,
2218 &pPort->pTxOobActive,
2219 &pPort->pTxOobFree );
2220 DBG_EXIT ( );
2221 }
2222
2223
2224 /**
2225 Verify the adapter's IP address
2226
2227 This support routine is called by EslSocketBindTest.
2228
2229 @param [in] pPort Address of an ::ESL_PORT structure.
2230 @param [in] pConfigData Address of the configuration data
2231
2232 @retval EFI_SUCCESS - The IP address is valid
2233 @retval EFI_NOT_STARTED - The IP address is invalid
2234
2235 **/
2236 EFI_STATUS
2237 EslTcp4VerifyLocalIpAddress (
2238 IN ESL_PORT * pPort,
2239 IN EFI_TCP4_CONFIG_DATA * pConfigData
2240 )
2241 {
2242 UINTN DataSize;
2243 EFI_TCP4_ACCESS_POINT * pAccess;
2244 EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo;
2245 EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol;
2246 ESL_SERVICE * pService;
2247 EFI_STATUS Status;
2248
2249 DBG_ENTER ( );
2250
2251 //
2252 // Use break instead of goto
2253 //
2254 pIfInfo = NULL;
2255 for ( ; ; ) {
2256 //
2257 // Determine if the IP address is specified
2258 //
2259 pAccess = &pConfigData->AccessPoint;
2260 DEBUG (( DEBUG_BIND,
2261 "UseDefaultAddress: %s\r\n",
2262 pAccess->UseDefaultAddress ? L"TRUE" : L"FALSE" ));
2263 DEBUG (( DEBUG_BIND,
2264 "Requested IP address: %d.%d.%d.%d\r\n",
2265 pAccess->StationAddress.Addr [ 0 ],
2266 pAccess->StationAddress.Addr [ 1 ],
2267 pAccess->StationAddress.Addr [ 2 ],
2268 pAccess->StationAddress.Addr [ 3 ]));
2269 if ( pAccess->UseDefaultAddress
2270 || (( 0 == pAccess->StationAddress.Addr [ 0 ])
2271 && ( 0 == pAccess->StationAddress.Addr [ 1 ])
2272 && ( 0 == pAccess->StationAddress.Addr [ 2 ])
2273 && ( 0 == pAccess->StationAddress.Addr [ 3 ])))
2274 {
2275 Status = EFI_SUCCESS;
2276 break;
2277 }
2278
2279 //
2280 // Open the configuration protocol
2281 //
2282 pService = pPort->pService;
2283 Status = gBS->OpenProtocol (
2284 pService->Controller,
2285 &gEfiIp4Config2ProtocolGuid,
2286 (VOID **)&pIpConfig2Protocol,
2287 NULL,
2288 NULL,
2289 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2290 );
2291 if ( EFI_ERROR ( Status )) {
2292 DEBUG (( DEBUG_ERROR,
2293 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
2294 Status ));
2295 break;
2296 }
2297
2298 //
2299 // Get the interface information size.
2300 //
2301 DataSize = 0;
2302 Status = pIpConfig2Protocol->GetData (
2303 pIpConfig2Protocol,
2304 Ip4Config2DataTypeInterfaceInfo,
2305 &DataSize,
2306 NULL
2307 );
2308 if ( EFI_BUFFER_TOO_SMALL != Status ) {
2309 DEBUG (( DEBUG_ERROR,
2310 "ERROR - Failed to get the interface information size, Status: %r\r\n",
2311 Status ));
2312 break;
2313 }
2314
2315 //
2316 // Allocate the interface information buffer
2317 //
2318 pIfInfo = AllocatePool ( DataSize );
2319 if ( NULL == pIfInfo ) {
2320 DEBUG (( DEBUG_ERROR,
2321 "ERROR - Not enough memory to allocate the interface information buffer!\r\n" ));
2322 Status = EFI_OUT_OF_RESOURCES;
2323 break;
2324 }
2325
2326 //
2327 // Get the interface info.
2328 //
2329 Status = pIpConfig2Protocol->GetData (
2330 pIpConfig2Protocol,
2331 Ip4Config2DataTypeInterfaceInfo,
2332 &DataSize,
2333 pIfInfo
2334 );
2335 if ( EFI_ERROR ( Status )) {
2336 DEBUG (( DEBUG_ERROR,
2337 "ERROR - Failed to return the interface info, Status: %r\r\n",
2338 Status ));
2339 break;
2340 }
2341
2342 //
2343 // Display the current configuration
2344 //
2345 DEBUG (( DEBUG_BIND,
2346 "Actual adapter IP address: %d.%d.%d.%d\r\n",
2347 pIfInfo->StationAddress.Addr [ 0 ],
2348 pIfInfo->StationAddress.Addr [ 1 ],
2349 pIfInfo->StationAddress.Addr [ 2 ],
2350 pIfInfo->StationAddress.Addr [ 3 ]));
2351
2352 //
2353 // Assume the port is not configured
2354 //
2355 Status = EFI_SUCCESS;
2356 if (( pAccess->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ])
2357 && ( pAccess->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ])
2358 && ( pAccess->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ])
2359 && ( pAccess->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) {
2360 break;
2361 }
2362
2363 //
2364 // The IP address did not match
2365 //
2366 Status = EFI_NOT_STARTED;
2367 break;
2368 }
2369
2370 //
2371 // Free the buffer if necessary
2372 //
2373 if ( NULL != pIfInfo ) {
2374 FreePool ( pIfInfo );
2375 }
2376
2377 //
2378 // Return the IP address status
2379 //
2380 DBG_EXIT_STATUS ( Status );
2381 return Status;
2382 }
2383
2384
2385 /**
2386 Interface between the socket layer and the network specific
2387 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2388 over TCPv4.
2389 **/
2390 CONST ESL_PROTOCOL_API cEslTcp4Api = {
2391 "TCPv4",
2392 IPPROTO_TCP,
2393 OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),
2394 OFFSET_OF ( ESL_LAYER, pTcp4List ),
2395 OFFSET_OF ( struct sockaddr_in, sin_zero ),
2396 sizeof ( struct sockaddr_in ),
2397 AF_INET,
2398 sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),
2399 OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
2400 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),
2401 TRUE,
2402 EADDRINUSE,
2403 EslTcp4Accept,
2404 EslTcp4ConnectPoll,
2405 EslTcp4ConnectStart,
2406 EslTcp4SocketIsConfigured,
2407 EslTcp4LocalAddressGet,
2408 EslTcp4LocalAddressSet,
2409 EslTcp4Listen,
2410 NULL, // OptionGet
2411 NULL, // OptionSet
2412 EslTcp4PacketFree,
2413 EslTcp4PortAllocate,
2414 EslTcp4PortClose,
2415 EslTcp4PortCloseOp,
2416 FALSE,
2417 EslTcp4Receive,
2418 EslTcp4RemoteAddressGet,
2419 EslTcp4RemoteAddressSet,
2420 EslTcp4RxComplete,
2421 EslTcp4RxStart,
2422 EslTcp4TxBuffer,
2423 EslTcp4TxComplete,
2424 EslTcp4TxOobComplete,
2425 (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp4VerifyLocalIpAddress
2426 };