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