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