]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Tcp4.c
Better handle transmit errors
[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
15 #include "Socket.h"
16
17
18 /**
19 Accept a network connection.
20
21 The SocketAccept routine waits for a network connection to the socket.
22 It is able to return the remote network address to the caller if
23 requested.
24
25 @param [in] pSocket Address of the socket structure.
26
27 @param [in] pSockAddr Address of a buffer to receive the remote
28 network address.
29
30 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
31 On output specifies the length of the
32 remote network address.
33
34 @retval EFI_SUCCESS Remote address is available
35 @retval Others Remote address not available
36
37 **/
38 EFI_STATUS
39 EslTcpAccept4 (
40 IN DT_SOCKET * pSocket,
41 IN struct sockaddr * pSockAddr,
42 IN OUT socklen_t * pSockAddrLength
43 )
44 {
45 DT_PORT * pPort;
46 struct sockaddr_in * pRemoteAddress;
47 DT_TCP4_CONTEXT * pTcp4;
48 UINT32 RemoteAddress;
49 EFI_STATUS Status;
50
51 DBG_ENTER ( );
52
53 //
54 // Validate the socket length
55 //
56 pRemoteAddress = (struct sockaddr_in *) pSockAddr;
57 if (( NULL == pSockAddrLength )
58 || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {
59 //
60 // Invalid socket address
61 //
62 Status = EFI_INVALID_PARAMETER;
63 pSocket->errno = EINVAL;
64 DEBUG (( DEBUG_ACCEPT,
65 "ERROR - Invalid address length\r\n" ));
66 }
67 else {
68 //
69 // Assume success
70 //
71 Status = EFI_SUCCESS;
72
73 //
74 // Locate the address context
75 //
76 pPort = pSocket->pPortList;
77 pTcp4 = &pPort->Context.Tcp4;
78
79 //
80 // Fill-in the remote address structure
81 //
82 ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));
83 pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );
84 pRemoteAddress->sin_family = AF_INET;
85 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
86 RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
87 RemoteAddress <<= 8;
88 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
89 RemoteAddress <<= 8;
90 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
91 RemoteAddress <<= 8;
92 RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
93 pRemoteAddress->sin_addr.s_addr = RemoteAddress;
94 }
95
96 //
97 // Return the operation status
98 //
99 DBG_EXIT_STATUS ( Status );
100 return Status;
101 }
102
103
104 /**
105 Bind a name to a socket.
106
107 The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.
108
109 @param [in] pSocket Address of the socket structure.
110
111 @param [in] pSockAddr Address of a sockaddr structure that contains the
112 connection point on the local machine. An IPv4 address
113 of INADDR_ANY specifies that the connection is made to
114 all of the network stacks on the platform. Specifying a
115 specific IPv4 address restricts the connection to the
116 network stack supporting that address. Specifying zero
117 for the port causes the network layer to assign a port
118 number from the dynamic range. Specifying a specific
119 port number causes the network layer to use that port.
120
121 @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
122
123 @retval EFI_SUCCESS - Socket successfully created
124
125 **/
126 EFI_STATUS
127 EslTcpBind4 (
128 IN DT_SOCKET * pSocket,
129 IN const struct sockaddr * pSockAddr,
130 IN socklen_t SockAddrLength
131 )
132 {
133 EFI_HANDLE ChildHandle;
134 DT_LAYER * pLayer;
135 DT_PORT * pPort;
136 DT_SERVICE * pService;
137 CONST struct sockaddr_in * pIp4Address;
138 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
139 EFI_STATUS Status;
140 EFI_STATUS TempStatus;
141
142 DBG_ENTER ( );
143
144 //
145 // Verify the socket layer synchronization
146 //
147 VERIFY_TPL ( TPL_SOCKETS );
148
149 //
150 // Assume success
151 //
152 pSocket->errno = 0;
153 Status = EFI_SUCCESS;
154
155 //
156 // Validate the address length
157 //
158 pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
159 if ( SockAddrLength >= ( sizeof ( *pIp4Address )
160 - sizeof ( pIp4Address->sin_zero ))) {
161
162 //
163 // Walk the list of services
164 //
165 pLayer = &mEslLayer;
166 pService = pLayer->pTcp4List;
167 while ( NULL != pService ) {
168 //
169 // Create the TCP port
170 //
171 pTcp4Service = pService->pInterface;
172 ChildHandle = NULL;
173 Status = pTcp4Service->CreateChild ( pTcp4Service,
174 &ChildHandle );
175 if ( !EFI_ERROR ( Status )) {
176 DEBUG (( DEBUG_BIND | DEBUG_POOL,
177 "0x%08x: Tcp4 port handle created\r\n",
178 ChildHandle ));
179
180 //
181 // Open the port
182 //
183 Status = EslTcpPortAllocate4 ( pSocket,
184 pService,
185 ChildHandle,
186 (UINT8 *) &pIp4Address->sin_addr.s_addr,
187 SwapBytes16 ( pIp4Address->sin_port ),
188 DEBUG_BIND,
189 &pPort );
190 }
191 else {
192 DEBUG (( DEBUG_BIND | DEBUG_POOL,
193 "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",
194 Status ));
195 ChildHandle = NULL;
196 }
197
198 //
199 // Close the port if necessary
200 //
201 if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
202 TempStatus = pTcp4Service->DestroyChild ( pTcp4Service,
203 ChildHandle );
204 if ( !EFI_ERROR ( TempStatus )) {
205 DEBUG (( DEBUG_BIND | DEBUG_POOL,
206 "0x%08x: Tcp4 port handle destroyed\r\n",
207 ChildHandle ));
208 }
209 else {
210 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
211 "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",
212 ChildHandle,
213 TempStatus ));
214 ASSERT ( EFI_SUCCESS == TempStatus );
215 }
216 }
217
218 //
219 // Set the next service
220 //
221 pService = pService->pNext;
222 }
223
224 //
225 // Verify that at least one network connection was found
226 //
227 if ( NULL == pSocket->pPortList ) {
228 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
229 "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
230 ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
231 ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
232 ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
233 pIp4Address->sin_addr.s_addr & 0xff,
234 pIp4Address->sin_addr.s_addr ));
235 pSocket->errno = EADDRNOTAVAIL;
236 Status = EFI_INVALID_PARAMETER;
237 }
238 }
239 else {
240 DEBUG (( DEBUG_BIND,
241 "ERROR - Invalid TCP4 address length: %d\r\n",
242 SockAddrLength ));
243 Status = EFI_INVALID_PARAMETER;
244 pSocket->errno = EINVAL;
245 }
246
247 //
248 // Return the operation status
249 //
250 DBG_EXIT_STATUS ( Status );
251 return Status;
252 }
253
254
255 /**
256 Attempt to connect to a remote TCP port
257
258 @param [in] pSocket Address of the socket structure.
259
260 @retval EFI_SUCCESS The connection was successfully established.
261 @retval EFI_NOT_READY The connection is in progress, call this routine again.
262 @retval Others The connection attempt failed.
263
264 **/
265 EFI_STATUS
266 EslTcpConnectAttempt4 (
267 IN DT_SOCKET * pSocket
268 )
269 {
270 DT_PORT * pPort;
271 DT_TCP4_CONTEXT * pTcp4;
272 EFI_TCP4_PROTOCOL * pTcp4Protocol;
273 EFI_STATUS Status;
274
275 DBG_ENTER ( );
276
277 //
278 // Determine if any more local adapters are available
279 //
280 pPort = pSocket->pPortList;
281 if ( NULL != pPort ) {
282 //
283 // Configure the port
284 //
285 pTcp4 = &pPort->Context.Tcp4;
286 pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;
287 pTcp4->ConfigData.TimeToLive = 255;
288 pTcp4Protocol = pTcp4->pProtocol;
289 Status = pTcp4Protocol->Configure ( pTcp4Protocol,
290 &pTcp4->ConfigData );
291 if ( EFI_ERROR ( Status )) {
292 DEBUG (( DEBUG_CONNECT,
293 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
294 Status ));
295 switch ( Status ) {
296 case EFI_ACCESS_DENIED:
297 pSocket->errno = EACCES;
298 break;
299
300 default:
301 case EFI_DEVICE_ERROR:
302 pSocket->errno = EIO;
303 break;
304
305 case EFI_INVALID_PARAMETER:
306 pSocket->errno = EADDRNOTAVAIL;
307 break;
308
309 case EFI_NO_MAPPING:
310 pSocket->errno = EAFNOSUPPORT;
311 break;
312
313 case EFI_OUT_OF_RESOURCES:
314 pSocket->errno = ENOBUFS;
315 break;
316
317 case EFI_UNSUPPORTED:
318 pSocket->errno = EOPNOTSUPP;
319 break;
320 }
321 }
322 else {
323 DEBUG (( DEBUG_CONNECT,
324 "0x%08x: Port configured\r\n",
325 pPort ));
326 pTcp4->bConfigured = TRUE;
327
328 //
329 // Attempt the connection to the remote system
330 //
331 Status = pTcp4Protocol->Connect ( pTcp4Protocol,
332 &pTcp4->ConnectToken );
333 if ( !EFI_ERROR ( Status )) {
334 //
335 // Connection in progress
336 //
337 pSocket->errno = EINPROGRESS;
338 Status = EFI_NOT_READY;
339 DEBUG (( DEBUG_CONNECT,
340 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
341 pPort,
342 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
343 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],
344 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],
345 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],
346 pTcp4->ConfigData.AccessPoint.RemotePort ));
347 }
348 else {
349 //
350 // Connection error
351 //
352 pSocket->errno = EINVAL;
353 DEBUG (( DEBUG_CONNECT,
354 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
355 pPort,
356 Status ));
357 }
358 }
359 }
360 else {
361 //
362 // No more local adapters available
363 //
364 pSocket->errno = ENETUNREACH;
365 Status = EFI_NO_RESPONSE;
366 }
367
368 //
369 // Return the operation status
370 //
371 DBG_EXIT_STATUS ( Status );
372 return Status;
373 }
374
375
376 /**
377 Process the remote connection attempt
378
379 A connection attempt to a remote system has just completed when
380 this routine is invoked. Release the port in the case of an
381 error and start a connection attempt on the next port. If the
382 connection attempt was successful, then release all of the other
383 ports.
384
385 @param Event The connect completion event
386
387 @param pPort The DT_PORT structure address
388
389 **/
390 VOID
391 EslTcpConnectComplete4 (
392 IN EFI_EVENT Event,
393 IN DT_PORT * pPort
394 )
395 {
396 BOOLEAN bRemoveFirstPort;
397 BOOLEAN bRemovePorts;
398 DT_PORT * pNextPort;
399 DT_SOCKET * pSocket;
400 DT_TCP4_CONTEXT * pTcp4;
401 EFI_STATUS Status;
402
403 DBG_ENTER ( );
404
405 //
406 // Locate the TCP context
407 //
408 pSocket = pPort->pSocket;
409 pTcp4 = &pPort->Context.Tcp4;
410
411 //
412 // Get the connection status
413 //
414 bRemoveFirstPort = FALSE;
415 bRemovePorts = FALSE;
416 Status = pTcp4->ConnectToken.CompletionToken.Status;
417 pSocket->ConnectStatus = Status;
418 if ( !EFI_ERROR ( Status )) {
419 //
420 // The connection was successful
421 //
422 DEBUG (( DEBUG_CONNECT,
423 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
424 pPort,
425 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
426 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
427 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
428 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
429 pTcp4->ConfigData.AccessPoint.RemotePort ));
430
431 //
432 // Remove the rest of the ports
433 //
434 bRemovePorts = TRUE;
435 }
436 else {
437 //
438 // The connection failed
439 //
440 DEBUG (( DEBUG_CONNECT,
441 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
442 pPort,
443 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],
444 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],
445 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],
446 pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],
447 pTcp4->ConfigData.AccessPoint.RemotePort,
448 Status ));
449
450 //
451 // Close the current port
452 //
453 Status = EslTcpPortClose4 ( pPort );
454 if ( !EFI_ERROR ( Status )) {
455 DEBUG (( DEBUG_CONNECT,
456 "0x%08x: Port closed\r\n",
457 pPort ));
458 }
459 else {
460 DEBUG (( DEBUG_CONNECT,
461 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
462 pPort,
463 Status ));
464 }
465
466 //
467 // Try to connect using the next port
468 //
469 Status = EslTcpConnectAttempt4 ( pSocket );
470 if ( EFI_NOT_READY != Status ) {
471 pSocket->ConnectStatus = Status;
472 bRemoveFirstPort = TRUE;
473 }
474 }
475
476 //
477 // Remove the ports if necessary
478 //
479 if ( bRemoveFirstPort || bRemovePorts ) {
480 //
481 // Remove the first port if necessary
482 //
483 pPort = pSocket->pPortList;
484 if (( !bRemoveFirstPort ) && ( NULL != pPort )) {
485 pPort = pPort->pLinkSocket;
486 }
487
488 //
489 // Remove the rest of the list
490 //
491 while ( NULL != pPort ) {
492 pNextPort = pPort->pLinkSocket;
493 EslTcpPortClose4 ( pPort );
494 if ( !EFI_ERROR ( Status )) {
495 DEBUG (( DEBUG_CONNECT,
496 "0x%08x: Port closed\r\n",
497 pPort ));
498 }
499 else {
500 DEBUG (( DEBUG_CONNECT,
501 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
502 pPort,
503 Status ));
504 }
505 pPort = pNextPort;
506 }
507
508 //
509 // Notify the poll routine
510 //
511 pSocket->bConnected = TRUE;
512 }
513
514 DBG_EXIT ( );
515 }
516
517
518 /**
519 Poll for completion of the connection attempt.
520
521 The ::TcpConnectPoll4 routine determines when the connection
522 attempt transitions from being in process to being complete.
523
524 @param [in] pSocket Address of the socket structure.
525
526 @retval EFI_SUCCESS The connection was successfully established.
527 @retval EFI_NOT_READY The connection is in progress, call this routine again.
528 @retval Others The connection attempt failed.
529
530 **/
531 EFI_STATUS
532 EslTcpConnectPoll4 (
533 IN DT_SOCKET * pSocket
534 )
535 {
536 EFI_STATUS Status;
537
538 DBG_ENTER ( );
539
540 //
541 // Determine if the connection is complete
542 //
543 if ( !pSocket->bConnected ) {
544 //
545 // Not connected
546 //
547 pSocket->errno = EAGAIN;
548 Status = EFI_NOT_READY;
549 }
550 else {
551 //
552 // The connection processing is complete
553 //
554 pSocket->bConnected = FALSE;
555
556 //
557 // Translate the connection status
558 //
559 Status = pSocket->ConnectStatus;
560 switch ( Status ) {
561 default:
562 case EFI_DEVICE_ERROR:
563 pSocket->errno = EIO;
564 break;
565
566 case EFI_ABORTED:
567 pSocket->errno = ECONNREFUSED;
568 break;
569
570 case EFI_INVALID_PARAMETER:
571 pSocket->errno = EINVAL;
572 break;
573
574 case EFI_NO_MAPPING:
575 case EFI_NO_RESPONSE:
576 pSocket->errno = EHOSTUNREACH;
577 break;
578
579 case EFI_NO_MEDIA:
580 pSocket->errno = ENETDOWN;
581 break;
582
583 case EFI_OUT_OF_RESOURCES:
584 pSocket->errno = ENOMEM;
585 break;
586
587 case EFI_SUCCESS:
588 pSocket->errno = 0;
589 pSocket->bConfigured = TRUE;
590 break;
591
592 case EFI_TIMEOUT:
593 pSocket->errno = ETIMEDOUT;
594 break;
595
596 case EFI_UNSUPPORTED:
597 pSocket->errno = ENOTSUP;
598 break;
599
600 case 0x80000069:
601 pSocket->errno = ECONNRESET;
602 break;
603 }
604 }
605
606 //
607 // Return the initialization status
608 //
609 DBG_EXIT_STATUS ( Status );
610 return Status;
611 }
612
613
614 /**
615 Connect to a remote system via the network.
616
617 The ::TcpConnectStart4= routine starts the connection processing
618 for a TCP4 port.
619
620 @param [in] pSocket Address of the socket structure.
621
622 @param [in] pSockAddr Network address of the remote system.
623
624 @param [in] SockAddrLength Length in bytes of the network address.
625
626 @retval EFI_SUCCESS The connection was successfully established.
627 @retval EFI_NOT_READY The connection is in progress, call this routine again.
628 @retval Others The connection attempt failed.
629
630 **/
631 EFI_STATUS
632 EslTcpConnectStart4 (
633 IN DT_SOCKET * pSocket,
634 IN const struct sockaddr * pSockAddr,
635 IN socklen_t SockAddrLength
636 )
637 {
638 struct sockaddr_in LocalAddress;
639 DT_PORT * pPort;
640 DT_TCP4_CONTEXT * pTcp4;
641 CONST struct sockaddr_in * pIp4Address;
642 EFI_STATUS Status;
643
644 DBG_ENTER ( );
645
646 //
647 // Validate the address length
648 //
649 Status = EFI_SUCCESS;
650 pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
651 if ( SockAddrLength >= ( sizeof ( *pIp4Address )
652 - sizeof ( pIp4Address->sin_zero ))) {
653 //
654 // Determine if BIND was already called
655 //
656 if ( NULL == pSocket->pPortList ) {
657 //
658 // Allow any local port
659 //
660 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
661 LocalAddress.sin_len = sizeof ( LocalAddress );
662 LocalAddress.sin_family = AF_INET;
663 Status = EslSocketBind ( &pSocket->SocketProtocol,
664 (struct sockaddr *)&LocalAddress,
665 LocalAddress.sin_len,
666 &pSocket->errno );
667 }
668 if ( NULL != pSocket->pPortList ) {
669 //
670 // Walk the list of ports
671 //
672 pPort = pSocket->pPortList;
673 while ( NULL != pPort ) {
674 //
675 // Set the remote address
676 //
677 pTcp4 = &pPort->Context.Tcp4;
678 *(UINT32 *)&pTcp4->ConfigData.AccessPoint.RemoteAddress = pIp4Address->sin_addr.s_addr;
679 pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pIp4Address->sin_port );
680
681 //
682 // Set the next port
683 //
684 pPort = pPort->pLinkSocket;
685 }
686
687 //
688 // Attempt a connection using the first adapter
689 //
690 Status = EslTcpConnectAttempt4 ( pSocket );
691 }
692 }
693 else {
694 DEBUG (( DEBUG_CONNECT,
695 "ERROR - Invalid TCP4 address length: %d\r\n",
696 SockAddrLength ));
697 Status = EFI_INVALID_PARAMETER;
698 pSocket->errno = EINVAL;
699 }
700
701 //
702 // Return the initialization status
703 //
704 DBG_EXIT_STATUS ( Status );
705 return Status;
706 }
707
708
709 /**
710 Initialize the TCP4 service.
711
712 This routine initializes the TCP4 service after its service binding
713 protocol was located on a controller.
714
715 @param [in] pService DT_SERVICE structure address
716
717 @retval EFI_SUCCESS The service was properly initialized
718 @retval other A failure occurred during the service initialization
719
720 **/
721 EFI_STATUS
722 EFIAPI
723 EslTcpInitialize4 (
724 IN DT_SERVICE * pService
725 )
726 {
727 DT_LAYER * pLayer;
728 EFI_STATUS Status;
729
730 DBG_ENTER ( );
731
732 //
733 // Identify the service
734 //
735 pService->NetworkType = NETWORK_TYPE_TCP4;
736
737 //
738 // Connect this service to the service list
739 //
740 pLayer = &mEslLayer;
741 pService->pNext = pLayer->pTcp4List;
742 pLayer->pTcp4List = pService;
743
744 //
745 // Assume the list is empty
746 //
747 Status = EFI_SUCCESS;
748
749 //
750 // Return the initialization status
751 //
752 DBG_EXIT_STATUS ( Status );
753 return Status;
754 }
755
756
757 /**
758 Get the local socket address
759
760 @param [in] pSocket Address of the socket structure.
761
762 @param [out] pAddress Network address to receive the local system address
763
764 @param [in,out] pAddressLength Length of the local network address structure
765
766 @retval EFI_SUCCESS - Address available
767 @retval Other - Failed to get the address
768
769 **/
770 EFI_STATUS
771 EslTcpGetLocalAddress4 (
772 IN DT_SOCKET * pSocket,
773 OUT struct sockaddr * pAddress,
774 IN OUT socklen_t * pAddressLength
775 )
776 {
777 socklen_t LengthInBytes;
778 DT_PORT * pPort;
779 struct sockaddr_in * pLocalAddress;
780 DT_TCP4_CONTEXT * pTcp4;
781 EFI_STATUS Status;
782
783 DBG_ENTER ( );
784
785 //
786 // Verify the socket layer synchronization
787 //
788 VERIFY_TPL ( TPL_SOCKETS );
789
790 //
791 // Verify that there is just a single connection
792 //
793 pPort = pSocket->pPortList;
794 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
795 //
796 // Verify the address length
797 //
798 LengthInBytes = sizeof ( struct sockaddr_in );
799 if ( LengthInBytes <= * pAddressLength ) {
800 //
801 // Return the local address
802 //
803 pTcp4 = &pPort->Context.Tcp4;
804 pLocalAddress = (struct sockaddr_in *)pAddress;
805 ZeroMem ( pLocalAddress, LengthInBytes );
806 pLocalAddress->sin_family = AF_INET;
807 pLocalAddress->sin_len = (uint8_t)LengthInBytes;
808 pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );
809 CopyMem ( &pLocalAddress->sin_addr,
810 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
811 sizeof ( pLocalAddress->sin_addr ));
812 pSocket->errno = 0;
813 Status = EFI_SUCCESS;
814 }
815 else {
816 pSocket->errno = EINVAL;
817 Status = EFI_INVALID_PARAMETER;
818 }
819 }
820 else {
821 pSocket->errno = ENOTCONN;
822 Status = EFI_NOT_STARTED;
823 }
824
825 //
826 // Return the operation status
827 //
828 DBG_EXIT_STATUS ( Status );
829 return Status;
830 }
831
832
833 /**
834 Get the remote socket address
835
836 @param [in] pSocket Address of the socket structure.
837
838 @param [out] pAddress Network address to receive the remote system address
839
840 @param [in,out] pAddressLength Length of the remote network address structure
841
842 @retval EFI_SUCCESS - Address available
843 @retval Other - Failed to get the address
844
845 **/
846 EFI_STATUS
847 EslTcpGetRemoteAddress4 (
848 IN DT_SOCKET * pSocket,
849 OUT struct sockaddr * pAddress,
850 IN OUT socklen_t * pAddressLength
851 )
852 {
853 socklen_t LengthInBytes;
854 DT_PORT * pPort;
855 struct sockaddr_in * pRemoteAddress;
856 DT_TCP4_CONTEXT * pTcp4;
857 EFI_STATUS Status;
858
859 DBG_ENTER ( );
860
861 //
862 // Verify the socket layer synchronization
863 //
864 VERIFY_TPL ( TPL_SOCKETS );
865
866 //
867 // Verify that there is just a single connection
868 //
869 pPort = pSocket->pPortList;
870 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
871 //
872 // Verify the address length
873 //
874 LengthInBytes = sizeof ( struct sockaddr_in );
875 if ( LengthInBytes <= * pAddressLength ) {
876 //
877 // Return the local address
878 //
879 pTcp4 = &pPort->Context.Tcp4;
880 pRemoteAddress = (struct sockaddr_in *)pAddress;
881 ZeroMem ( pRemoteAddress, LengthInBytes );
882 pRemoteAddress->sin_family = AF_INET;
883 pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
884 pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
885 CopyMem ( &pRemoteAddress->sin_addr,
886 &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],
887 sizeof ( pRemoteAddress->sin_addr ));
888 pSocket->errno = 0;
889 Status = EFI_SUCCESS;
890 }
891 else {
892 pSocket->errno = EINVAL;
893 Status = EFI_INVALID_PARAMETER;
894 }
895 }
896 else {
897 pSocket->errno = ENOTCONN;
898 Status = EFI_NOT_STARTED;
899 }
900
901 //
902 // Return the operation status
903 //
904 DBG_EXIT_STATUS ( Status );
905 return Status;
906 }
907
908
909 /**
910 Establish the known port to listen for network connections.
911
912 The ::Tcp4Listen routine places the port into a state that enables connection
913 attempts. Connections are placed into FIFO order in a queue to be serviced
914 by the application. The application calls the ::Tcp4Accept routine to remove
915 the next connection from the queue and get the associated socket. The
916 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
917 documentation for the listen routine is available online for reference.
918
919 @param [in] pSocket Address of the socket structure.
920
921 @retval EFI_SUCCESS - Socket successfully created
922 @retval Other - Failed to enable the socket for listen
923
924 **/
925 EFI_STATUS
926 EslTcpListen4 (
927 IN DT_SOCKET * pSocket
928 )
929 {
930 DT_PORT * pNextPort;
931 DT_PORT * pPort;
932 DT_TCP4_CONTEXT * pTcp4;
933 EFI_TCP4_PROTOCOL * pTcp4Protocol;
934 EFI_STATUS Status;
935
936 DBG_ENTER ( );
937
938 //
939 // Verify the socket layer synchronization
940 //
941 VERIFY_TPL ( TPL_SOCKETS );
942
943 //
944 // Use for/break instead of goto
945 //
946 for ( ; ; ) {
947 //
948 // Assume no ports are available
949 //
950 pSocket->errno = EOPNOTSUPP;
951 Status = EFI_NOT_READY;
952
953 //
954 // Walk the list of ports
955 //
956 pPort = pSocket->pPortList;
957 while ( NULL != pPort ) {
958 //
959 // Assume success
960 //
961 pSocket->errno = 0;
962
963 //
964 // Use for/break insteak of goto
965 //
966 for ( ; ; ) {
967 //
968 // Create the listen completion event
969 //
970 pTcp4 = &pPort->Context.Tcp4;
971 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
972 TPL_SOCKETS,
973 (EFI_EVENT_NOTIFY)EslTcpListenComplete4,
974 pPort,
975 &pTcp4->ListenToken.CompletionToken.Event );
976 if ( EFI_ERROR ( Status )) {
977 DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
978 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
979 Status ));
980 pSocket->errno = ENOMEM;
981 break;
982 }
983 DEBUG (( DEBUG_POOL,
984 "0x%08x: Created listen completion event\r\n",
985 pTcp4->ListenToken.CompletionToken.Event ));
986
987 //
988 // Configure the port
989 //
990 pTcp4Protocol = pTcp4->pProtocol;
991 Status = pTcp4Protocol->Configure ( pTcp4Protocol,
992 &pTcp4->ConfigData );
993 if ( EFI_ERROR ( Status )) {
994 DEBUG (( DEBUG_LISTEN,
995 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
996 Status ));
997 switch ( Status ) {
998 case EFI_ACCESS_DENIED:
999 pSocket->errno = EACCES;
1000 break;
1001
1002 default:
1003 case EFI_DEVICE_ERROR:
1004 pSocket->errno = EIO;
1005 break;
1006
1007 case EFI_INVALID_PARAMETER:
1008 pSocket->errno = EADDRNOTAVAIL;
1009 break;
1010
1011 case EFI_NO_MAPPING:
1012 pSocket->errno = EAFNOSUPPORT;
1013 break;
1014
1015 case EFI_OUT_OF_RESOURCES:
1016 pSocket->errno = ENOBUFS;
1017 break;
1018
1019 case EFI_UNSUPPORTED:
1020 pSocket->errno = EOPNOTSUPP;
1021 break;
1022 }
1023 break;
1024 }
1025 DEBUG (( DEBUG_LISTEN,
1026 "0x%08x: Port configured\r\n",
1027 pPort ));
1028 pTcp4->bConfigured = TRUE;
1029
1030 //
1031 // Start the listen operation on the port
1032 //
1033 Status = pTcp4Protocol->Accept ( pTcp4Protocol,
1034 &pTcp4->ListenToken );
1035 if ( EFI_ERROR ( Status )) {
1036 DEBUG (( DEBUG_LISTEN,
1037 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
1038 Status ));
1039 switch ( Status ) {
1040 case EFI_ACCESS_DENIED:
1041 pSocket->errno = EACCES;
1042 break;
1043
1044 default:
1045 case EFI_DEVICE_ERROR:
1046 pSocket->errno = EIO;
1047 break;
1048
1049 case EFI_INVALID_PARAMETER:
1050 pSocket->errno = EADDRNOTAVAIL;
1051 break;
1052
1053 case EFI_NOT_STARTED:
1054 pSocket->errno = ENETDOWN;
1055 break;
1056
1057 case EFI_OUT_OF_RESOURCES:
1058 pSocket->errno = ENOBUFS;
1059 break;
1060 }
1061 break;
1062 }
1063 DEBUG (( DEBUG_LISTEN,
1064 "0x%08x: Listen pending on Port\r\n",
1065 pPort ));
1066
1067 //
1068 // Listen is pending on this port
1069 //
1070 break;
1071 }
1072
1073 //
1074 // Get the next port
1075 //
1076 pNextPort = pPort->pLinkSocket;
1077
1078 //
1079 // Close the port upon error
1080 //
1081 if ( EFI_ERROR ( Status ))
1082 {
1083 EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
1084 }
1085
1086 //
1087 // Set the next port
1088 //
1089 pPort = pNextPort;
1090 }
1091
1092 //
1093 // Determine if any ports are in the listen state
1094 //
1095 if ( NULL == pSocket->pPortList ) {
1096 //
1097 // No ports in the listen state
1098 //
1099 pSocket->MaxFifoDepth = 0;
1100
1101 //
1102 // Return the last error detected
1103 //
1104 break;
1105 }
1106
1107 //
1108 // Mark the socket as configured
1109 //
1110 pSocket->bConfigured = TRUE;
1111
1112 //
1113 // All done
1114 //
1115 DEBUG (( DEBUG_LISTEN,
1116 "0x%08x: pSocket - Listen pending on socket\r\n",
1117 pSocket ));
1118 break;
1119 }
1120
1121 //
1122 // Return the operation status
1123 //
1124 DBG_EXIT_STATUS ( Status );
1125 return Status;
1126 }
1127
1128
1129 /**
1130 Process the connection attempt
1131
1132 A system has initiated a connection attempt with a socket in the
1133 listen state. Attempt to complete the connection.
1134
1135 @param Event The listen completion event
1136
1137 @param pPort The DT_PORT structure address
1138
1139 **/
1140 VOID
1141 EslTcpListenComplete4 (
1142 IN EFI_EVENT Event,
1143 IN DT_PORT * pPort
1144 )
1145 {
1146 EFI_HANDLE ChildHandle;
1147 EFI_TCP4_CONFIG_DATA * pConfigData;
1148 DT_LAYER * pLayer;
1149 DT_PORT * pNewPort;
1150 DT_SOCKET * pNewSocket;
1151 DT_SOCKET * pSocket;
1152 DT_TCP4_CONTEXT * pTcp4;
1153 EFI_TCP4_PROTOCOL * pTcp4Protocol;
1154 EFI_STATUS Status;
1155 EFI_HANDLE TcpPortHandle;
1156 EFI_STATUS TempStatus;
1157
1158 DBG_ENTER ( );
1159
1160 //
1161 // Assume success
1162 //
1163 Status = EFI_SUCCESS;
1164
1165 //
1166 // Determine if this connection fits into the connection FIFO
1167 //
1168 pSocket = pPort->pSocket;
1169 TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;
1170 if (( SOCKET_STATE_LISTENING == pSocket->State )
1171 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {
1172 //
1173 // Allocate a socket for this connection
1174 //
1175 ChildHandle = NULL;
1176 pLayer = &mEslLayer;
1177 Status = EslSocketAllocate ( &ChildHandle,
1178 DEBUG_CONNECTION,
1179 &pNewSocket );
1180 if ( !EFI_ERROR ( Status )) {
1181 //
1182 // Clone the socket parameters
1183 //
1184 pNewSocket->Domain = pSocket->Domain;
1185 pNewSocket->Protocol = pSocket->Protocol;
1186 pNewSocket->Type = pSocket->Type;
1187
1188 //
1189 // Allocate a port for this connection
1190 //
1191 pTcp4 = &pPort->Context.Tcp4;
1192 Status = EslTcpPortAllocate4 ( pNewSocket,
1193 pPort->pService,
1194 TcpPortHandle,
1195 &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],
1196 0,
1197 DEBUG_CONNECTION,
1198 &pNewPort );
1199 if ( !EFI_ERROR ( Status )) {
1200 //
1201 // Restart the listen operation on the port
1202 //
1203 pTcp4Protocol = pTcp4->pProtocol;
1204 Status = pTcp4Protocol->Accept ( pTcp4Protocol,
1205 &pTcp4->ListenToken );
1206
1207 //
1208 // Close the TCP port using SocketClose
1209 //
1210 TcpPortHandle = NULL;
1211 pTcp4 = &pNewPort->Context.Tcp4;
1212 pTcp4->bConfigured = TRUE;
1213
1214 //
1215 // Check for an accept call error
1216 //
1217 if ( !EFI_ERROR ( Status )) {
1218 //
1219 // Get the port configuration
1220 //
1221 pConfigData = &pTcp4->ConfigData;
1222 pConfigData->ControlOption = &pTcp4->Option;
1223 pTcp4Protocol = pTcp4->pProtocol;
1224 Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,
1225 NULL,
1226 pConfigData,
1227 NULL,
1228 NULL,
1229 NULL );
1230 if ( !EFI_ERROR ( Status )) {
1231 //
1232 // Add the new socket to the connection FIFO
1233 //
1234 if ( NULL == pSocket->pFifoTail ) {
1235 //
1236 // First connection
1237 //
1238 pSocket->pFifoHead = pNewSocket;
1239 }
1240 else {
1241 //
1242 // Add to end of list.
1243 //
1244 pSocket->pFifoTail->pNextConnection = pNewSocket;
1245 }
1246 pSocket->pFifoTail = pNewSocket;
1247 pSocket->FifoDepth += 1;
1248
1249 //
1250 // Update the socket state
1251 //
1252 pNewSocket->State = SOCKET_STATE_IN_FIFO;
1253
1254 //
1255 // Log the connection
1256 //
1257 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
1258 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
1259 pNewSocket,
1260 pConfigData->AccessPoint.StationAddress.Addr[0],
1261 pConfigData->AccessPoint.StationAddress.Addr[1],
1262 pConfigData->AccessPoint.StationAddress.Addr[2],
1263 pConfigData->AccessPoint.StationAddress.Addr[3],
1264 pConfigData->AccessPoint.StationPort,
1265 pConfigData->AccessPoint.RemoteAddress.Addr[0],
1266 pConfigData->AccessPoint.RemoteAddress.Addr[1],
1267 pConfigData->AccessPoint.RemoteAddress.Addr[2],
1268 pConfigData->AccessPoint.RemoteAddress.Addr[3],
1269 pConfigData->AccessPoint.RemotePort ));
1270 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
1271 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
1272 pSocket,
1273 pNewSocket,
1274 pSocket->FifoDepth ));
1275
1276 //
1277 // Start the receive operation
1278 //
1279 EslTcpRxStart4 ( pNewPort );
1280 }
1281 else {
1282 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
1283 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1284 pNewPort,
1285 Status ));
1286 }
1287 }
1288 else {
1289 //
1290 // The listen failed on this port
1291 //
1292 DEBUG (( DEBUG_LISTEN | DEBUG_INFO,
1293 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1294 pPort,
1295 Status ));
1296
1297 //
1298 // Close the listening port
1299 //
1300 EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );
1301 }
1302 }
1303
1304 //
1305 // Done with the socket if necessary
1306 //
1307 if ( EFI_ERROR ( Status )) {
1308 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,
1309 TRUE,
1310 &pSocket->errno );
1311 ASSERT ( EFI_SUCCESS == TempStatus );
1312 }
1313 }
1314 }
1315 else {
1316 DEBUG (( DEBUG_CONNECTION,
1317 "0x%08x: Socket FIFO full, connection refused\r\n",
1318 pSocket ));
1319
1320 //
1321 // The FIFO is full or the socket is in the wrong state
1322 //
1323 Status = EFI_BUFFER_TOO_SMALL;
1324 }
1325
1326 //
1327 // Close the connection if necessary
1328 //
1329 if (( EFI_ERROR ( Status ))
1330 && ( NULL == TcpPortHandle )) {
1331 //
1332 // TODO: Finish this code path
1333 // The new connection does not fit into the connection FIFO
1334 //
1335 // Process:
1336 // Call close
1337 // Release the resources
1338
1339 }
1340
1341 DBG_EXIT ( );
1342 }
1343
1344
1345 /**
1346 Allocate and initialize a DT_PORT structure.
1347
1348 @param [in] pSocket Address of the socket structure.
1349 @param [in] pService Address of the DT_SERVICE structure.
1350 @param [in] ChildHandle TCP4 child handle
1351 @param [in] pIpAddress Buffer containing IP4 network address of the local host
1352 @param [in] PortNumber Tcp4 port number
1353 @param [in] DebugFlags Flags for debug messages
1354 @param [out] ppPort Buffer to receive new DT_PORT structure address
1355
1356 @retval EFI_SUCCESS - Socket successfully created
1357
1358 **/
1359 EFI_STATUS
1360 EslTcpPortAllocate4 (
1361 IN DT_SOCKET * pSocket,
1362 IN DT_SERVICE * pService,
1363 IN EFI_HANDLE ChildHandle,
1364 IN CONST UINT8 * pIpAddress,
1365 IN UINT16 PortNumber,
1366 IN UINTN DebugFlags,
1367 OUT DT_PORT ** ppPort
1368 )
1369 {
1370 UINTN LengthInBytes;
1371 EFI_TCP4_ACCESS_POINT * pAccessPoint;
1372 DT_LAYER * pLayer;
1373 DT_PORT * pPort;
1374 DT_TCP4_CONTEXT * pTcp4;
1375 EFI_STATUS Status;
1376
1377 DBG_ENTER ( );
1378
1379 //
1380 // Use for/break instead of goto
1381 for ( ; ; ) {
1382 //
1383 // Allocate a port structure
1384 //
1385 pLayer = &mEslLayer;
1386 LengthInBytes = sizeof ( *pPort );
1387 Status = gBS->AllocatePool ( EfiRuntimeServicesData,
1388 LengthInBytes,
1389 (VOID **)&pPort );
1390 if ( EFI_ERROR ( Status )) {
1391 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
1392 "ERROR - Failed to allocate the port structure, Status: %r\r\n",
1393 Status ));
1394 pSocket->errno = ENOMEM;
1395 pPort = NULL;
1396 break;
1397 }
1398 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
1399 "0x%08x: Allocate pPort, %d bytes\r\n",
1400 pPort,
1401 LengthInBytes ));
1402
1403 //
1404 // Initialize the port
1405 //
1406 ZeroMem ( pPort, LengthInBytes );
1407 pPort->Signature = PORT_SIGNATURE;
1408 pPort->pService = pService;
1409 pPort->pSocket = pSocket;
1410 pPort->pfnCloseStart = EslTcpPortCloseStart4;
1411 pPort->DebugFlags = DebugFlags;
1412
1413 //
1414 // Allocate the receive event
1415 //
1416 pTcp4 = &pPort->Context.Tcp4;
1417 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1418 TPL_SOCKETS,
1419 (EFI_EVENT_NOTIFY)EslTcpRxComplete4,
1420 pPort,
1421 &pTcp4->RxToken.CompletionToken.Event);
1422 if ( EFI_ERROR ( Status )) {
1423 DEBUG (( DEBUG_ERROR | DebugFlags,
1424 "ERROR - Failed to create the receive event, Status: %r\r\n",
1425 Status ));
1426 pSocket->errno = ENOMEM;
1427 break;
1428 }
1429 DEBUG (( DEBUG_RX | DEBUG_POOL,
1430 "0x%08x: Created receive event\r\n",
1431 pTcp4->RxToken.CompletionToken.Event ));
1432
1433 //
1434 // Allocate the urgent transmit event
1435 //
1436 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1437 TPL_SOCKETS,
1438 (EFI_EVENT_NOTIFY)EslTcpTxOobComplete4,
1439 pPort,
1440 &pTcp4->TxOobToken.CompletionToken.Event);
1441 if ( EFI_ERROR ( Status )) {
1442 DEBUG (( DEBUG_ERROR | DebugFlags,
1443 "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",
1444 Status ));
1445 pSocket->errno = ENOMEM;
1446 break;
1447 }
1448 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1449 "0x%08x: Created urgent transmit event\r\n",
1450 pTcp4->TxOobToken.CompletionToken.Event ));
1451
1452 //
1453 // Allocate the normal transmit event
1454 //
1455 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1456 TPL_SOCKETS,
1457 (EFI_EVENT_NOTIFY)EslTcpTxComplete4,
1458 pPort,
1459 &pTcp4->TxToken.CompletionToken.Event);
1460 if ( EFI_ERROR ( Status )) {
1461 DEBUG (( DEBUG_ERROR | DebugFlags,
1462 "ERROR - Failed to create the normal transmit event, Status: %r\r\n",
1463 Status ));
1464 pSocket->errno = ENOMEM;
1465 break;
1466 }
1467 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1468 "0x%08x: Created normal transmit event\r\n",
1469 pTcp4->TxToken.CompletionToken.Event ));
1470
1471 //
1472 // Allocate the close event
1473 //
1474 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1475 TPL_SOCKETS,
1476 (EFI_EVENT_NOTIFY)EslTcpPortCloseComplete4,
1477 pPort,
1478 &pTcp4->CloseToken.CompletionToken.Event);
1479 if ( EFI_ERROR ( Status )) {
1480 DEBUG (( DEBUG_ERROR | DebugFlags,
1481 "ERROR - Failed to create the close event, Status: %r\r\n",
1482 Status ));
1483 pSocket->errno = ENOMEM;
1484 break;
1485 }
1486 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1487 "0x%08x: Created close event\r\n",
1488 pTcp4->CloseToken.CompletionToken.Event ));
1489
1490 //
1491 // Allocate the connection event
1492 //
1493 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
1494 TPL_SOCKETS,
1495 (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,
1496 pPort,
1497 &pTcp4->ConnectToken.CompletionToken.Event);
1498 if ( EFI_ERROR ( Status )) {
1499 DEBUG (( DEBUG_ERROR | DebugFlags,
1500 "ERROR - Failed to create the connect event, Status: %r\r\n",
1501 Status ));
1502 pSocket->errno = ENOMEM;
1503 break;
1504 }
1505 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
1506 "0x%08x: Created connect event\r\n",
1507 pTcp4->ConnectToken.CompletionToken.Event ));
1508
1509 //
1510 // Open the port protocol
1511 //
1512 Status = gBS->OpenProtocol (
1513 ChildHandle,
1514 &gEfiTcp4ProtocolGuid,
1515 (VOID **) &pTcp4->pProtocol,
1516 pLayer->ImageHandle,
1517 NULL,
1518 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
1519 if ( EFI_ERROR ( Status )) {
1520 DEBUG (( DEBUG_ERROR | DebugFlags,
1521 "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",
1522 pTcp4->Handle ));
1523 pSocket->errno = EEXIST;
1524 break;
1525 }
1526 DEBUG (( DebugFlags,
1527 "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",
1528 pTcp4->pProtocol,
1529 ChildHandle ));
1530
1531 //
1532 // Set the port address
1533 //
1534 pTcp4->Handle = ChildHandle;
1535 pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;
1536 pAccessPoint->StationPort = PortNumber;
1537 if (( 0 == pIpAddress[0])
1538 && ( 0 == pIpAddress[1])
1539 && ( 0 == pIpAddress[2])
1540 && ( 0 == pIpAddress[3])) {
1541 pAccessPoint->UseDefaultAddress = TRUE;
1542 }
1543 else {
1544 pAccessPoint->StationAddress.Addr[0] = pIpAddress[0];
1545 pAccessPoint->StationAddress.Addr[1] = pIpAddress[1];
1546 pAccessPoint->StationAddress.Addr[2] = pIpAddress[2];
1547 pAccessPoint->StationAddress.Addr[3] = pIpAddress[3];
1548 pAccessPoint->SubnetMask.Addr[0] = 0xff;
1549 pAccessPoint->SubnetMask.Addr[1] = 0xff;
1550 pAccessPoint->SubnetMask.Addr[2] = 0xff;
1551 pAccessPoint->SubnetMask.Addr[3] = 0xff;
1552 }
1553 pAccessPoint->ActiveFlag = FALSE;
1554 pTcp4->ConfigData.TimeToLive = 255;
1555
1556 //
1557 // Verify the socket layer synchronization
1558 //
1559 VERIFY_TPL ( TPL_SOCKETS );
1560
1561 //
1562 // Add this port to the socket
1563 //
1564 pPort->pLinkSocket = pSocket->pPortList;
1565 pSocket->pPortList = pPort;
1566 DEBUG (( DebugFlags,
1567 "0x%08x: Socket adding port: 0x%08x\r\n",
1568 pSocket,
1569 pPort ));
1570
1571 //
1572 // Add this port to the service
1573 //
1574 pPort->pLinkService = pService->pPortList;
1575 pService->pPortList = pPort;
1576
1577 //
1578 // Return the port
1579 //
1580 *ppPort = pPort;
1581 break;
1582 }
1583
1584 //
1585 // Clean up after the error if necessary
1586 //
1587 if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {
1588 //
1589 // Close the port
1590 //
1591 EslTcpPortClose4 ( pPort );
1592 }
1593 //
1594 // Return the operation status
1595 //
1596 DBG_EXIT_STATUS ( Status );
1597 return Status;
1598 }
1599
1600
1601 /**
1602 Close a TCP4 port.
1603
1604 This routine releases the resources allocated by
1605 ::TcpPortAllocate4().
1606
1607 @param [in] pPort Address of the port structure.
1608
1609 @retval EFI_SUCCESS The port is closed
1610 @retval other Port close error
1611
1612 **/
1613 EFI_STATUS
1614 EslTcpPortClose4 (
1615 IN DT_PORT * pPort
1616 )
1617 {
1618 UINTN DebugFlags;
1619 DT_LAYER * pLayer;
1620 DT_PACKET * pPacket;
1621 DT_PORT * pPreviousPort;
1622 DT_SERVICE * pService;
1623 DT_SOCKET * pSocket;
1624 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;
1625 DT_TCP4_CONTEXT * pTcp4;
1626 EFI_STATUS Status;
1627
1628 DBG_ENTER ( );
1629
1630 //
1631 // Verify the socket layer synchronization
1632 //
1633 VERIFY_TPL ( TPL_SOCKETS );
1634
1635 //
1636 // Locate the port in the socket list
1637 //
1638 Status = EFI_SUCCESS;
1639 pLayer = &mEslLayer;
1640 DebugFlags = pPort->DebugFlags;
1641 pSocket = pPort->pSocket;
1642 pPreviousPort = pSocket->pPortList;
1643 if ( pPreviousPort == pPort ) {
1644 //
1645 // Remove this port from the head of the socket list
1646 //
1647 pSocket->pPortList = pPort->pLinkSocket;
1648 }
1649 else {
1650 //
1651 // Locate the port in the middle of the socket list
1652 //
1653 while (( NULL != pPreviousPort )
1654 && ( pPreviousPort->pLinkSocket != pPort )) {
1655 pPreviousPort = pPreviousPort->pLinkSocket;
1656 }
1657 if ( NULL != pPreviousPort ) {
1658 //
1659 // Remove the port from the middle of the socket list
1660 //
1661 pPreviousPort->pLinkSocket = pPort->pLinkSocket;
1662 }
1663 }
1664
1665 //
1666 // Locate the port in the service list
1667 //
1668 pService = pPort->pService;
1669 pPreviousPort = pService->pPortList;
1670 if ( pPreviousPort == pPort ) {
1671 //
1672 // Remove this port from the head of the service list
1673 //
1674 pService->pPortList = pPort->pLinkService;
1675 }
1676 else {
1677 //
1678 // Locate the port in the middle of the service list
1679 //
1680 while (( NULL != pPreviousPort )
1681 && ( pPreviousPort->pLinkService != pPort )) {
1682 pPreviousPort = pPreviousPort->pLinkService;
1683 }
1684 if ( NULL != pPreviousPort ) {
1685 //
1686 // Remove the port from the middle of the service list
1687 //
1688 pPreviousPort->pLinkService = pPort->pLinkService;
1689 }
1690 }
1691
1692 //
1693 // Empty the urgent receive queue
1694 //
1695 pTcp4 = &pPort->Context.Tcp4;
1696 while ( NULL != pSocket->pRxOobPacketListHead ) {
1697 pPacket = pSocket->pRxOobPacketListHead;
1698 pSocket->pRxOobPacketListHead = pPacket->pNext;
1699 pSocket->RxOobBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
1700 EslSocketPacketFree ( pPacket, DEBUG_RX );
1701 }
1702 pSocket->pRxOobPacketListTail = NULL;
1703 ASSERT ( 0 == pSocket->RxOobBytes );
1704
1705 //
1706 // Empty the receive queue
1707 //
1708 while ( NULL != pSocket->pRxPacketListHead ) {
1709 pPacket = pSocket->pRxPacketListHead;
1710 pSocket->pRxPacketListHead = pPacket->pNext;
1711 pSocket->RxBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
1712 EslSocketPacketFree ( pPacket, DEBUG_RX );
1713 }
1714 pSocket->pRxPacketListTail = NULL;
1715 ASSERT ( 0 == pSocket->RxBytes );
1716
1717 //
1718 // Empty the receive free queue
1719 //
1720 while ( NULL != pSocket->pRxFree ) {
1721 pPacket = pSocket->pRxFree;
1722 pSocket->pRxFree = pPacket->pNext;
1723 EslSocketPacketFree ( pPacket, DEBUG_RX );
1724 }
1725
1726 //
1727 // Done with the connect event
1728 //
1729 if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {
1730 Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );
1731 if ( !EFI_ERROR ( Status )) {
1732 DEBUG (( DebugFlags | DEBUG_POOL,
1733 "0x%08x: Closed connect event\r\n",
1734 pTcp4->ConnectToken.CompletionToken.Event ));
1735 }
1736 else {
1737 DEBUG (( DEBUG_ERROR | DebugFlags,
1738 "ERROR - Failed to close the connect event, Status: %r\r\n",
1739 Status ));
1740 ASSERT ( EFI_SUCCESS == Status );
1741 }
1742 }
1743
1744 //
1745 // Done with the close event
1746 //
1747 if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {
1748 Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );
1749 if ( !EFI_ERROR ( Status )) {
1750 DEBUG (( DebugFlags | DEBUG_POOL,
1751 "0x%08x: Closed close event\r\n",
1752 pTcp4->CloseToken.CompletionToken.Event ));
1753 }
1754 else {
1755 DEBUG (( DEBUG_ERROR | DebugFlags,
1756 "ERROR - Failed to close the close event, Status: %r\r\n",
1757 Status ));
1758 ASSERT ( EFI_SUCCESS == Status );
1759 }
1760 }
1761
1762 //
1763 // Done with the listen completion event
1764 //
1765 if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {
1766 Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );
1767 if ( !EFI_ERROR ( Status )) {
1768 DEBUG (( DebugFlags | DEBUG_POOL,
1769 "0x%08x: Closed listen completion event\r\n",
1770 pTcp4->ListenToken.CompletionToken.Event ));
1771 }
1772 else {
1773 DEBUG (( DEBUG_ERROR | DebugFlags,
1774 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1775 Status ));
1776 ASSERT ( EFI_SUCCESS == Status );
1777 }
1778 }
1779
1780 //
1781 // Done with the receive event
1782 //
1783 if ( NULL != pTcp4->RxToken.CompletionToken.Event ) {
1784 Status = gBS->CloseEvent ( pTcp4->RxToken.CompletionToken.Event );
1785 if ( !EFI_ERROR ( Status )) {
1786 DEBUG (( DebugFlags | DEBUG_POOL,
1787 "0x%08x: Closed receive event\r\n",
1788 pTcp4->RxToken.CompletionToken.Event ));
1789 }
1790 else {
1791 DEBUG (( DEBUG_ERROR | DebugFlags,
1792 "ERROR - Failed to close the receive event, Status: %r\r\n",
1793 Status ));
1794 ASSERT ( EFI_SUCCESS == Status );
1795 }
1796 }
1797
1798 //
1799 // Done with the normal transmit event
1800 //
1801 if ( NULL != pTcp4->TxToken.CompletionToken.Event ) {
1802 Status = gBS->CloseEvent ( pTcp4->TxToken.CompletionToken.Event );
1803 if ( !EFI_ERROR ( Status )) {
1804 DEBUG (( DebugFlags | DEBUG_POOL,
1805 "0x%08x: Closed normal transmit event\r\n",
1806 pTcp4->TxToken.CompletionToken.Event ));
1807 }
1808 else {
1809 DEBUG (( DEBUG_ERROR | DebugFlags,
1810 "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
1811 Status ));
1812 ASSERT ( EFI_SUCCESS == Status );
1813 }
1814 }
1815
1816 //
1817 // Done with the urgent transmit event
1818 //
1819 if ( NULL != pTcp4->TxOobToken.CompletionToken.Event ) {
1820 Status = gBS->CloseEvent ( pTcp4->TxOobToken.CompletionToken.Event );
1821 if ( !EFI_ERROR ( Status )) {
1822 DEBUG (( DebugFlags | DEBUG_POOL,
1823 "0x%08x: Closed urgent transmit event\r\n",
1824 pTcp4->TxOobToken.CompletionToken.Event ));
1825 }
1826 else {
1827 DEBUG (( DEBUG_ERROR | DebugFlags,
1828 "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",
1829 Status ));
1830 ASSERT ( EFI_SUCCESS == Status );
1831 }
1832 }
1833
1834 //
1835 // Done with the TCP protocol
1836 //
1837 pTcp4Service = pService->pInterface;
1838 if ( NULL != pTcp4->pProtocol ) {
1839 Status = gBS->CloseProtocol ( pTcp4->Handle,
1840 &gEfiTcp4ProtocolGuid,
1841 pLayer->ImageHandle,
1842 NULL );
1843 if ( !EFI_ERROR ( Status )) {
1844 DEBUG (( DebugFlags,
1845 "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",
1846 pTcp4->pProtocol,
1847 pTcp4->Handle ));
1848 }
1849 else {
1850 DEBUG (( DEBUG_ERROR | DebugFlags,
1851 "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
1852 pTcp4->Handle,
1853 Status ));
1854 ASSERT ( EFI_SUCCESS == Status );
1855 }
1856 }
1857
1858 //
1859 // Done with the TCP port
1860 //
1861 if ( NULL != pTcp4->Handle ) {
1862 Status = pTcp4Service->DestroyChild ( pTcp4Service,
1863 pTcp4->Handle );
1864 if ( !EFI_ERROR ( Status )) {
1865 DEBUG (( DebugFlags | DEBUG_POOL,
1866 "0x%08x: Tcp4 port handle destroyed\r\n",
1867 pTcp4->Handle ));
1868 }
1869 else {
1870 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
1871 "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",
1872 Status ));
1873 ASSERT ( EFI_SUCCESS == Status );
1874 }
1875 }
1876
1877 //
1878 // Release the port structure
1879 //
1880 Status = gBS->FreePool ( pPort );
1881 if ( !EFI_ERROR ( Status )) {
1882 DEBUG (( DebugFlags | DEBUG_POOL,
1883 "0x%08x: Free pPort, %d bytes\r\n",
1884 pPort,
1885 sizeof ( *pPort )));
1886 }
1887 else {
1888 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
1889 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
1890 pPort,
1891 Status ));
1892 ASSERT ( EFI_SUCCESS == Status );
1893 }
1894
1895 //
1896 // Return the operation status
1897 //
1898 DBG_EXIT_STATUS ( Status );
1899 return Status;
1900 }
1901
1902
1903 /**
1904 Process the port close completion
1905
1906 @param Event The close completion event
1907
1908 @param pPort The DT_PORT structure address
1909
1910 **/
1911 VOID
1912 EslTcpPortCloseComplete4 (
1913 IN EFI_EVENT Event,
1914 IN DT_PORT * pPort
1915 )
1916 {
1917 EFI_STATUS Status;
1918
1919 DBG_ENTER ( );
1920
1921 //
1922 // Update the port state
1923 //
1924 pPort->State = PORT_STATE_CLOSE_DONE;
1925
1926 //
1927 // Release the resources once the receive operation completes
1928 //
1929 Status = EslTcpPortCloseRxDone4 ( pPort );
1930 DBG_EXIT_STATUS ( Status );
1931 }
1932
1933
1934 /**
1935 Start the close operation on a TCP4 port, state 1.
1936
1937 Closing a port goes through the following states:
1938 1. Port close starting - Mark the port as closing and wait for transmission to complete
1939 2. Port TX close done - Transmissions complete, close the port and abort the receives
1940 3. Port RX close done - Receive operations complete, close the port
1941 4. Port closed - Release the port resources
1942
1943 @param [in] pPort Address of the port structure.
1944 @param [in] bCloseNow Set TRUE to abort active transfers
1945 @param [in] DebugFlags Flags for debug messages
1946
1947 @retval EFI_SUCCESS The port is closed, not normally returned
1948 @retval EFI_NOT_READY The port has started the closing process
1949 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1950 most likely the routine was called already.
1951
1952 **/
1953 EFI_STATUS
1954 EslTcpPortCloseStart4 (
1955 IN DT_PORT * pPort,
1956 IN BOOLEAN bCloseNow,
1957 IN UINTN DebugFlags
1958 )
1959 {
1960 DT_SOCKET * pSocket;
1961 EFI_STATUS Status;
1962
1963 DBG_ENTER ( );
1964
1965 //
1966 // Verify the socket layer synchronization
1967 //
1968 VERIFY_TPL ( TPL_SOCKETS );
1969
1970 //
1971 // Mark the port as closing
1972 //
1973 Status = EFI_ALREADY_STARTED;
1974 pSocket = pPort->pSocket;
1975 pSocket->errno = EALREADY;
1976 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
1977
1978 //
1979 // Update the port state
1980 //
1981 pPort->State = PORT_STATE_CLOSE_STARTED;
1982 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
1983 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
1984 pPort ));
1985 pPort->bCloseNow = bCloseNow;
1986 pPort->DebugFlags = DebugFlags;
1987
1988 //
1989 // Determine if transmits are complete
1990 //
1991 Status = EslTcpPortCloseTxDone4 ( pPort );
1992 }
1993
1994 //
1995 // Return the operation status
1996 //
1997 DBG_EXIT_STATUS ( Status );
1998 return Status;
1999 }
2000
2001
2002 /**
2003 Port close state 3
2004
2005 Continue the close operation after the receive is complete.
2006
2007 @param [in] pPort Address of the port structure.
2008
2009 @retval EFI_SUCCESS The port is closed
2010 @retval EFI_NOT_READY The port is still closing
2011 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
2012 most likely the routine was called already.
2013
2014 **/
2015 EFI_STATUS
2016 EslTcpPortCloseRxDone4 (
2017 IN DT_PORT * pPort
2018 )
2019 {
2020 PORT_STATE PortState;
2021 DT_TCP4_CONTEXT * pTcp4;
2022 EFI_STATUS Status;
2023
2024 DBG_ENTER ( );
2025
2026 //
2027 // Verify the socket layer synchronization
2028 //
2029 VERIFY_TPL ( TPL_SOCKETS );
2030
2031 //
2032 // Verify that the port is closing
2033 //
2034 Status = EFI_ALREADY_STARTED;
2035 PortState = pPort->State;
2036 if (( PORT_STATE_CLOSE_TX_DONE == PortState )
2037 || ( PORT_STATE_CLOSE_DONE == PortState )) {
2038 //
2039 // Determine if the receive operation is pending
2040 //
2041 Status = EFI_NOT_READY;
2042 pTcp4 = &pPort->Context.Tcp4;
2043 if ( NULL == pTcp4->pReceivePending ) {
2044 //
2045 // The receive operation is complete
2046 // Update the port state
2047 //
2048 pPort->State = PORT_STATE_CLOSE_RX_DONE;
2049 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2050 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
2051 pPort ));
2052
2053 //
2054 // Determine if the close operation has completed
2055 //
2056 if ( PORT_STATE_CLOSE_DONE == PortState ) {
2057 //
2058 // The close operation has completed
2059 // Release the port resources
2060 //
2061 Status = EslTcpPortClose4 ( pPort );
2062 }
2063 else
2064 {
2065 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2066 "0x%08x: Port Close: Close operation still pending!\r\n",
2067 pPort ));
2068 }
2069 }
2070 else {
2071 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2072 "0x%08x: Port Close: Receive still pending!\r\n",
2073 pPort ));
2074 }
2075 }
2076
2077 //
2078 // Return the operation status
2079 //
2080 DBG_EXIT_STATUS ( Status );
2081 return Status;
2082 }
2083
2084
2085 /**
2086 Port close state 2
2087
2088 Continue the close operation after the transmission is complete.
2089
2090 @param [in] pPort Address of the port structure.
2091
2092 @retval EFI_SUCCESS The port is closed, not normally returned
2093 @retval EFI_NOT_READY The port is still closing
2094 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
2095 most likely the routine was called already.
2096
2097 **/
2098 EFI_STATUS
2099 EslTcpPortCloseTxDone4 (
2100 IN DT_PORT * pPort
2101 )
2102 {
2103 DT_SOCKET * pSocket;
2104 DT_TCP4_CONTEXT * pTcp4;
2105 EFI_TCP4_PROTOCOL * pTcp4Protocol;
2106 EFI_STATUS Status;
2107
2108 DBG_ENTER ( );
2109
2110 //
2111 // Verify the socket layer synchronization
2112 //
2113 VERIFY_TPL ( TPL_SOCKETS );
2114
2115 //
2116 // All transmissions are complete or must be stopped
2117 // Mark the port as TX complete
2118 //
2119 Status = EFI_ALREADY_STARTED;
2120 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
2121 //
2122 // Verify that the transmissions are complete
2123 //
2124 pSocket = pPort->pSocket;
2125 if ( pPort->bCloseNow
2126 || ( EFI_SUCCESS != pSocket->TxError )
2127 || (( 0 == pSocket->TxOobBytes )
2128 && ( 0 == pSocket->TxBytes ))) {
2129 //
2130 // Start the close operation on the port
2131 //
2132 pTcp4 = &pPort->Context.Tcp4;
2133 pTcp4->CloseToken.AbortOnClose = FALSE;
2134 pTcp4Protocol = pTcp4->pProtocol;
2135 if ( !pTcp4->bConfigured ) {
2136 //
2137 // Skip the close operation since the port is not
2138 // configured
2139 //
2140 // Update the port state
2141 //
2142 pPort->State = PORT_STATE_CLOSE_DONE;
2143 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2144 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
2145 pPort ));
2146 Status = EFI_SUCCESS;
2147 }
2148 else {
2149 //
2150 // Close the configured port
2151 //
2152 Status = pTcp4Protocol->Close ( pTcp4Protocol,
2153 &pTcp4->CloseToken );
2154 if ( !EFI_ERROR ( Status )) {
2155 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
2156 "0x%08x: Port close started\r\n",
2157 pPort ));
2158
2159 //
2160 // Update the port state
2161 //
2162 pPort->State = PORT_STATE_CLOSE_TX_DONE;
2163 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2164 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
2165 pPort ));
2166 }
2167 else {
2168 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
2169 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
2170 pPort,
2171 Status ));
2172 ASSERT ( EFI_SUCCESS == Status );
2173 }
2174 }
2175
2176 //
2177 // Determine if the receive operation is pending
2178 //
2179 if ( !EFI_ERROR ( Status )) {
2180 Status = EslTcpPortCloseRxDone4 ( pPort );
2181 }
2182 }
2183 else {
2184 //
2185 // Transmissions are still active, exit
2186 //
2187 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
2188 "0x%08x: Port Close: Transmits are still pending!\r\n",
2189 pPort ));
2190 Status = EFI_NOT_READY;
2191 pSocket->errno = EAGAIN;
2192 }
2193 }
2194
2195 //
2196 // Return the operation status
2197 //
2198 DBG_EXIT_STATUS ( Status );
2199 return Status;
2200 }
2201
2202
2203 /**
2204 Receive data from a network connection.
2205
2206
2207 @param [in] pSocket Address of a DT_SOCKET structure
2208
2209 @param [in] Flags Message control flags
2210
2211 @param [in] BufferLength Length of the the buffer
2212
2213 @param [in] pBuffer Address of a buffer to receive the data.
2214
2215 @param [in] pDataLength Number of received data bytes in the buffer.
2216
2217 @param [out] pAddress Network address to receive the remote system address
2218
2219 @param [in,out] pAddressLength Length of the remote network address structure
2220
2221 @retval EFI_SUCCESS - Socket data successfully received
2222
2223 **/
2224 EFI_STATUS
2225 EslTcpReceive4 (
2226 IN DT_SOCKET * pSocket,
2227 IN INT32 Flags,
2228 IN size_t BufferLength,
2229 IN UINT8 * pBuffer,
2230 OUT size_t * pDataLength,
2231 OUT struct sockaddr * pAddress,
2232 IN OUT socklen_t * pAddressLength
2233 )
2234 {
2235 socklen_t AddressLength;
2236 size_t BytesToCopy;
2237 in_addr_t IpAddress;
2238 size_t LengthInBytes;
2239 DT_PACKET * pPacket;
2240 DT_PORT * pPort;
2241 DT_PACKET ** ppQueueHead;
2242 DT_PACKET ** ppQueueTail;
2243 struct sockaddr_in * pRemoteAddress;
2244 size_t * pRxDataBytes;
2245 DT_TCP4_CONTEXT * pTcp4;
2246 struct sockaddr_in RemoteAddress;
2247 EFI_STATUS Status;
2248
2249 DBG_ENTER ( );
2250
2251 //
2252 // Assume failure
2253 //
2254 Status = EFI_UNSUPPORTED;
2255 pSocket->errno = ENOTCONN;
2256
2257 //
2258 // Verify that the socket is connected
2259 //
2260 if (( SOCKET_STATE_CONNECTED == pSocket->State )
2261 || ( PORT_STATE_RX_ERROR == pSocket->State )) {
2262 //
2263 // Locate the port
2264 //
2265 pPort = pSocket->pPortList;
2266 if ( NULL != pPort ) {
2267 //
2268 // Determine the queue head
2269 //
2270 pTcp4 = &pPort->Context.Tcp4;
2271 if ( 0 != ( Flags & MSG_OOB )) {
2272 ppQueueHead = &pSocket->pRxOobPacketListHead;
2273 ppQueueTail = &pSocket->pRxOobPacketListTail;
2274 pRxDataBytes = &pSocket->RxOobBytes;
2275 }
2276 else {
2277 ppQueueHead = &pSocket->pRxPacketListHead;
2278 ppQueueTail = &pSocket->pRxPacketListTail;
2279 pRxDataBytes = &pSocket->RxBytes;
2280 }
2281
2282 //
2283 // Determine if there is any data on the queue
2284 //
2285 pPacket = *ppQueueHead;
2286 if ( NULL != pPacket ) {
2287 //
2288 // Validate the return address parameters
2289 //
2290 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
2291 //
2292 // Return the remote system address if requested
2293 //
2294 if ( NULL != pAddress ) {
2295 //
2296 // Build the remote address
2297 //
2298 ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
2299 RemoteAddress.sin_len = sizeof ( RemoteAddress );
2300 RemoteAddress.sin_family = AF_INET;
2301 IpAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];
2302 IpAddress <<= 8;
2303 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];
2304 IpAddress <<= 8;
2305 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];
2306 IpAddress <<= 8;
2307 IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];
2308 RemoteAddress.sin_addr.s_addr = IpAddress;
2309 RemoteAddress.sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );
2310
2311 //
2312 // Copy the address
2313 //
2314 pRemoteAddress = (struct sockaddr_in *)pAddress;
2315 AddressLength = sizeof ( *pRemoteAddress );
2316 if ( AddressLength > *pAddressLength ) {
2317 AddressLength = *pAddressLength;
2318 }
2319 CopyMem ( pRemoteAddress,
2320 &RemoteAddress,
2321 AddressLength );
2322
2323 //
2324 // Update the address length
2325 //
2326 *pAddressLength = AddressLength;
2327 }
2328
2329 //
2330 // Copy the received data
2331 //
2332 LengthInBytes = 0;
2333 do {
2334 //
2335 // Determine the amount of received data
2336 //
2337 BytesToCopy = pPacket->Op.Tcp4Rx.ValidBytes;
2338 if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
2339 BytesToCopy = BufferLength - LengthInBytes;
2340 }
2341 LengthInBytes += BytesToCopy;
2342
2343 //
2344 // Move the data into the buffer
2345 //
2346 DEBUG (( DEBUG_RX,
2347 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
2348 pPort,
2349 pPacket,
2350 pBuffer,
2351 BytesToCopy ));
2352 CopyMem ( pBuffer, pPacket->Op.Tcp4Rx.pBuffer, BytesToCopy );
2353
2354 //
2355 // Determine if the data is being read
2356 //
2357 if ( 0 == ( Flags & MSG_PEEK )) {
2358 //
2359 // Account for the bytes consumed
2360 //
2361 pPacket->Op.Tcp4Rx.pBuffer += BytesToCopy;
2362 pPacket->Op.Tcp4Rx.ValidBytes -= BytesToCopy;
2363 *pRxDataBytes -= BytesToCopy;
2364 DEBUG (( DEBUG_RX,
2365 "0x%08x: Port account for 0x%08x bytes\r\n",
2366 pPort,
2367 BytesToCopy ));
2368
2369 //
2370 // Determine if the entire packet was consumed
2371 //
2372 if (( 0 == pPacket->Op.Tcp4Rx.ValidBytes )
2373 || ( SOCK_STREAM != pSocket->Type )) {
2374 //
2375 // All done with this packet
2376 // Account for any discarded data
2377 //
2378 *pRxDataBytes -= pPacket->Op.Tcp4Rx.ValidBytes;
2379 if ( 0 != pPacket->Op.Tcp4Rx.ValidBytes ) {
2380 DEBUG (( DEBUG_RX,
2381 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
2382 pPort,
2383 pPacket->Op.Tcp4Rx.ValidBytes ));
2384 }
2385
2386 //
2387 // Remove this packet from the queue
2388 //
2389 *ppQueueHead = pPacket->pNext;
2390 if ( NULL == *ppQueueHead ) {
2391 *ppQueueTail = NULL;
2392 }
2393
2394 //
2395 // Move the packet to the free queue
2396 //
2397 pPacket->pNext = pSocket->pRxFree;
2398 pSocket->pRxFree = pPacket;
2399 DEBUG (( DEBUG_RX,
2400 "0x%08x: Port freeing packet 0x%08x\r\n",
2401 pPort,
2402 pPacket ));
2403
2404 //
2405 // Restart this receive operation if necessary
2406 //
2407 if (( NULL == pTcp4->pReceivePending )
2408 && ( MAX_RX_DATA > pSocket->RxBytes )) {
2409 EslTcpRxStart4 ( pPort );
2410 }
2411 }
2412 }
2413
2414 //
2415 // Get the next packet
2416 //
2417 pPacket = *ppQueueHead;
2418 } while (( SOCK_STREAM == pSocket->Type )
2419 && ( NULL != pPacket )
2420 && ( 0 == ( Flags & MSG_PEEK ))
2421 && ( BufferLength > LengthInBytes ));
2422
2423 //
2424 // Return the data length
2425 //
2426 *pDataLength = LengthInBytes;
2427
2428 //
2429 // Successful operation
2430 //
2431 Status = EFI_SUCCESS;
2432 pSocket->errno = 0;
2433 }
2434 else {
2435 //
2436 // Bad return address pointer and length
2437 //
2438 Status = EFI_INVALID_PARAMETER;
2439 pSocket->errno = EINVAL;
2440 }
2441 }
2442 else {
2443 //
2444 // The queue is empty
2445 // Determine if it is time to return the receive error
2446 //
2447 if ( EFI_ERROR ( pSocket->RxError )
2448 && ( NULL == pSocket->pRxPacketListHead )
2449 && ( NULL == pSocket->pRxOobPacketListHead )) {
2450 Status = pSocket->RxError;
2451 pSocket->RxError = EFI_SUCCESS;
2452 switch ( Status ) {
2453 default:
2454 pSocket->errno = EIO;
2455 break;
2456
2457 case EFI_CONNECTION_FIN:
2458 //
2459 // Continue to return zero bytes received when the
2460 // peer has successfully closed the connection
2461 //
2462 pSocket->RxError = EFI_CONNECTION_FIN;
2463 *pDataLength = 0;
2464 pSocket->errno = 0;
2465 Status = EFI_SUCCESS;
2466 break;
2467
2468 case EFI_CONNECTION_REFUSED:
2469 pSocket->errno = ECONNREFUSED;
2470 break;
2471
2472 case EFI_CONNECTION_RESET:
2473 pSocket->errno = ECONNRESET;
2474 break;
2475
2476 case EFI_HOST_UNREACHABLE:
2477 pSocket->errno = EHOSTUNREACH;
2478 break;
2479
2480 case EFI_NETWORK_UNREACHABLE:
2481 pSocket->errno = ENETUNREACH;
2482 break;
2483
2484 case EFI_PORT_UNREACHABLE:
2485 pSocket->errno = EPROTONOSUPPORT;
2486 break;
2487
2488 case EFI_PROTOCOL_UNREACHABLE:
2489 pSocket->errno = ENOPROTOOPT;
2490 break;
2491 }
2492 }
2493 else {
2494 Status = EFI_NOT_READY;
2495 pSocket->errno = EAGAIN;
2496 }
2497 }
2498 }
2499 }
2500
2501 //
2502 // Return the operation status
2503 //
2504 DBG_EXIT_STATUS ( Status );
2505 return Status;
2506 }
2507
2508
2509 /**
2510 Cancel the receive operations
2511
2512 @param [in] pSocket Address of a DT_SOCKET structure
2513
2514 @retval EFI_SUCCESS - The cancel was successful
2515
2516 **/
2517 EFI_STATUS
2518 EslTcpRxCancel4 (
2519 IN DT_SOCKET * pSocket
2520 )
2521 {
2522 DT_PACKET * pPacket;
2523 DT_PORT * pPort;
2524 DT_TCP4_CONTEXT * pTcp4;
2525 EFI_TCP4_PROTOCOL * pTcp4Protocol;
2526 EFI_STATUS Status;
2527
2528 DBG_ENTER ( );
2529
2530 //
2531 // Assume failure
2532 //
2533 Status = EFI_NOT_FOUND;
2534
2535 //
2536 // Locate the port
2537 //
2538 pPort = pSocket->pPortList;
2539 if ( NULL != pPort ) {
2540 //
2541 // Determine if a receive is pending
2542 //
2543 pTcp4 = &pPort->Context.Tcp4;
2544 pPacket = pTcp4->pReceivePending;
2545 if ( NULL != pPacket ) {
2546 //
2547 // Attempt to cancel the receive operation
2548 //
2549 pTcp4Protocol = pTcp4->pProtocol;
2550 Status = pTcp4Protocol->Cancel ( pTcp4Protocol,
2551 &pTcp4->RxToken.CompletionToken );
2552 if ( EFI_NOT_FOUND == Status ) {
2553 //
2554 // The receive is complete
2555 //
2556 Status = EFI_SUCCESS;
2557 }
2558 }
2559 }
2560
2561 //
2562 // Return the operation status
2563 //
2564 DBG_EXIT_STATUS ( Status );
2565 return Status;
2566 }
2567
2568
2569 /**
2570 Process the receive completion
2571
2572 Buffer the data that was just received.
2573
2574 @param Event The receive completion event
2575
2576 @param pPort The DT_PORT structure address
2577
2578 **/
2579 VOID
2580 EslTcpRxComplete4 (
2581 IN EFI_EVENT Event,
2582 IN DT_PORT * pPort
2583 )
2584 {
2585 BOOLEAN bUrgent;
2586 size_t LengthInBytes;
2587 DT_PACKET * pPacket;
2588 DT_PACKET * pPrevious;
2589 DT_SOCKET * pSocket;
2590 DT_TCP4_CONTEXT * pTcp4;
2591 EFI_STATUS Status;
2592
2593 DBG_ENTER ( );
2594
2595 //
2596 // Mark this receive complete
2597 //
2598 pTcp4 = &pPort->Context.Tcp4;
2599 pPacket = pTcp4->pReceivePending;
2600 pTcp4->pReceivePending = NULL;
2601
2602 //
2603 // Determine if this receive was successful
2604 //
2605 pSocket = pPort->pSocket;
2606 Status = pTcp4->RxToken.CompletionToken.Status;
2607 if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
2608 //
2609 // Set the buffer size and address
2610 //
2611 pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
2612 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
2613 pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;
2614 pPacket->pNext = NULL;
2615
2616 //
2617 // Queue this packet
2618 //
2619 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
2620 if ( bUrgent ) {
2621 //
2622 // Add packet to the urgent list
2623 //
2624 pPrevious = pSocket->pRxOobPacketListTail;
2625 if ( NULL == pPrevious ) {
2626 pSocket->pRxOobPacketListHead = pPacket;
2627 }
2628 else {
2629 pPrevious->pNext = pPacket;
2630 }
2631 pSocket->pRxOobPacketListTail = pPacket;
2632
2633 //
2634 // Account for the urgent data
2635 //
2636 pSocket->RxOobBytes += LengthInBytes;
2637 }
2638 else {
2639 //
2640 // Add packet to the normal list
2641 //
2642 pPrevious = pSocket->pRxPacketListTail;
2643 if ( NULL == pPrevious ) {
2644 pSocket->pRxPacketListHead = pPacket;
2645 }
2646 else {
2647 pPrevious->pNext = pPacket;
2648 }
2649 pSocket->pRxPacketListTail = pPacket;
2650
2651 //
2652 // Account for the normal data
2653 //
2654 pSocket->RxBytes += LengthInBytes;
2655 }
2656
2657 //
2658 // Log the received data
2659 //
2660 DEBUG (( DEBUG_RX | DEBUG_INFO,
2661 "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",
2662 pPacket,
2663 pPort,
2664 LengthInBytes,
2665 bUrgent ? L"urgent" : L"normal" ));
2666
2667 //
2668 // Attempt to restart this receive operation
2669 //
2670 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
2671 EslTcpRxStart4 ( pPort );
2672 }
2673 else {
2674 DEBUG (( DEBUG_RX,
2675 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
2676 pPort,
2677 pSocket->RxBytes ));
2678 }
2679 }
2680 else
2681 {
2682 DEBUG (( DEBUG_RX | DEBUG_INFO,
2683 "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
2684 pPacket,
2685 pPort,
2686 Status ));
2687
2688 //
2689 // Receive error, free the packet save the error
2690 //
2691 EslSocketPacketFree ( pPacket, DEBUG_RX );
2692 if ( !EFI_ERROR ( pSocket->RxError )) {
2693 pSocket->RxError = Status;
2694 }
2695
2696 //
2697 // Update the port state
2698 //
2699 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
2700 EslTcpPortCloseRxDone4 ( pPort );
2701 }
2702 else {
2703 if ( EFI_ERROR ( Status )) {
2704 pPort->State = PORT_STATE_RX_ERROR;
2705 }
2706 }
2707 }
2708
2709 DBG_EXIT ( );
2710 }
2711
2712
2713 /**
2714 Start a receive operation
2715
2716 @param [in] pPort Address of the DT_PORT structure.
2717
2718 **/
2719 VOID
2720 EslTcpRxStart4 (
2721 IN DT_PORT * pPort
2722 )
2723 {
2724 size_t LengthInBytes;
2725 DT_PACKET * pPacket;
2726 DT_SOCKET * pSocket;
2727 DT_TCP4_CONTEXT * pTcp4;
2728 EFI_TCP4_PROTOCOL * pTcp4Protocol;
2729 EFI_STATUS Status;
2730
2731 DBG_ENTER ( );
2732
2733 //
2734 // Determine if a receive is already pending
2735 //
2736 Status = EFI_SUCCESS;
2737 pPacket = NULL;
2738 pSocket = pPort->pSocket;
2739 pTcp4 = &pPort->Context.Tcp4;
2740 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
2741 if (( NULL == pTcp4->pReceivePending )
2742 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
2743 //
2744 // Determine if there are any free packets
2745 //
2746 pPacket = pSocket->pRxFree;
2747 LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
2748 if ( NULL != pPacket ) {
2749 //
2750 // Remove this packet from the free list
2751 //
2752 pSocket->pRxFree = pPacket->pNext;
2753 DEBUG (( DEBUG_RX,
2754 "0x%08x: Port removed packet 0x%08x from free list\r\n",
2755 pPort,
2756 pPacket ));
2757 }
2758 else {
2759 //
2760 // Allocate a packet structure
2761 //
2762 Status = EslSocketPacketAllocate ( &pPacket,
2763 sizeof ( pPacket->Op.Tcp4Rx ),
2764 DEBUG_RX );
2765 if ( EFI_ERROR ( Status )) {
2766 pPacket = NULL;
2767 DEBUG (( DEBUG_ERROR | DEBUG_RX,
2768 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
2769 pPort,
2770 Status ));
2771 }
2772 }
2773
2774 //
2775 // Determine if a packet is available
2776 //
2777 if ( NULL != pPacket ) {
2778 //
2779 // Initialize the buffer for receive
2780 //
2781 pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
2782 pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;
2783 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
2784 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;
2785 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];
2786 pTcp4->pReceivePending = pPacket;
2787
2788 //
2789 // Start the receive on the packet
2790 //
2791 pTcp4Protocol = pTcp4->pProtocol;
2792 Status = pTcp4Protocol->Receive ( pTcp4Protocol,
2793 &pTcp4->RxToken );
2794 if ( !EFI_ERROR ( Status )) {
2795 DEBUG (( DEBUG_RX | DEBUG_INFO,
2796 "0x%08x: Packet receive pending on port 0x%08x\r\n",
2797 pPacket,
2798 pPort ));
2799 }
2800 else {
2801 DEBUG (( DEBUG_RX | DEBUG_INFO,
2802 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
2803 pPort,
2804 Status ));
2805 pTcp4->pReceivePending = NULL;
2806 if ( !EFI_ERROR ( pSocket->RxError )) {
2807 //
2808 // Save the error status
2809 //
2810 pSocket->RxError = Status;
2811 }
2812 }
2813 }
2814 }
2815 }
2816
2817 DBG_EXIT ( );
2818 }
2819
2820
2821 /**
2822 Shutdown the TCP4 service.
2823
2824 This routine undoes the work performed by ::TcpInitialize4.
2825
2826 @param [in] pService DT_SERVICE structure address
2827
2828 **/
2829 VOID
2830 EFIAPI
2831 EslTcpShutdown4 (
2832 IN DT_SERVICE * pService
2833 )
2834 {
2835 DT_LAYER * pLayer;
2836 DT_PORT * pPort;
2837 DT_SERVICE * pPreviousService;
2838
2839 DBG_ENTER ( );
2840
2841 //
2842 // Verify the socket layer synchronization
2843 //
2844 VERIFY_TPL ( TPL_SOCKETS );
2845
2846 //
2847 // Walk the list of ports
2848 //
2849 do {
2850 pPort = pService->pPortList;
2851 if ( NULL != pPort ) {
2852 //
2853 // Remove the port from the port list
2854 //
2855 pService->pPortList = pPort->pLinkService;
2856
2857 //
2858 // Close the port
2859 // TODO: Fix this
2860 //
2861 // pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );
2862 }
2863 } while ( NULL != pPort );
2864
2865 //
2866 // Remove the service from the service list
2867 //
2868 pLayer = &mEslLayer;
2869 pPreviousService = pLayer->pTcp4List;
2870 if ( pService == pPreviousService ) {
2871 //
2872 // Remove the service from the beginning of the list
2873 //
2874 pLayer->pTcp4List = pService->pNext;
2875 }
2876 else {
2877 //
2878 // Remove the service from the middle of the list
2879 //
2880 while ( NULL != pPreviousService ) {
2881 if ( pService == pPreviousService->pNext ) {
2882 pPreviousService->pNext = pService->pNext;
2883 break;
2884 }
2885 }
2886 }
2887
2888 DBG_EXIT ( );
2889 }
2890
2891
2892 /**
2893 Determine if the socket is configured.
2894
2895
2896 @param [in] pSocket Address of a DT_SOCKET structure
2897
2898 @retval EFI_SUCCESS - The port is connected
2899 @retval EFI_NOT_STARTED - The port is not connected
2900
2901 **/
2902 EFI_STATUS
2903 EslTcpSocketIsConfigured4 (
2904 IN DT_SOCKET * pSocket
2905 )
2906 {
2907 EFI_STATUS Status;
2908
2909 DBG_ENTER ( );
2910
2911 //
2912 // Determine the socket configuration status
2913 //
2914 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
2915
2916 //
2917 // Return the port connected state.
2918 //
2919 DBG_EXIT_STATUS ( Status );
2920 return Status;
2921 }
2922
2923
2924 /**
2925 Buffer data for transmission over a network connection.
2926
2927 This routine is called by the socket layer API to buffer
2928 data for transmission. When necessary, this routine will
2929 start the transmit engine that performs the data transmission
2930 on the network connection.
2931
2932 The transmit engine uses two queues, one for urgent (out-of-band)
2933 data and the other for normal data. The urgent data is provided
2934 to TCP as soon as it is available, allowing the TCP layer to
2935 schedule transmission of the urgent data between packets of normal
2936 data.
2937
2938 Transmission errors are returned during the next transmission or
2939 during the close operation. Only buffering errors are returned
2940 during the current transmission attempt.
2941
2942 @param [in] pSocket Address of a DT_SOCKET structure
2943
2944 @param [in] Flags Message control flags
2945
2946 @param [in] BufferLength Length of the the buffer
2947
2948 @param [in] pBuffer Address of a buffer to receive the data.
2949
2950 @param [in] pDataLength Number of received data bytes in the buffer.
2951
2952 @retval EFI_SUCCESS - Socket data successfully buffered
2953
2954 **/
2955 EFI_STATUS
2956 EslTcpTxBuffer4 (
2957 IN DT_SOCKET * pSocket,
2958 IN int Flags,
2959 IN size_t BufferLength,
2960 IN CONST UINT8 * pBuffer,
2961 OUT size_t * pDataLength
2962 )
2963 {
2964 BOOLEAN bUrgent;
2965 DT_PACKET * pPacket;
2966 DT_PACKET * pPreviousPacket;
2967 DT_PACKET ** ppPacket;
2968 DT_PACKET ** ppQueueHead;
2969 DT_PACKET ** ppQueueTail;
2970 DT_PORT * pPort;
2971 DT_TCP4_CONTEXT * pTcp4;
2972 EFI_TCP4_IO_TOKEN * pToken;
2973 size_t * pTxBytes;
2974 EFI_TCP4_TRANSMIT_DATA * pTxData;
2975 EFI_STATUS Status;
2976 EFI_TPL TplPrevious;
2977
2978 DBG_ENTER ( );
2979
2980 //
2981 // Assume failure
2982 //
2983 Status = EFI_UNSUPPORTED;
2984 pSocket->errno = ENOTCONN;
2985 * pDataLength = 0;
2986
2987 //
2988 // Verify that the socket is connected
2989 //
2990 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
2991 //
2992 // Locate the port
2993 //
2994 pPort = pSocket->pPortList;
2995 if ( NULL != pPort ) {
2996 //
2997 // Determine the queue head
2998 //
2999 pTcp4 = &pPort->Context.Tcp4;
3000 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
3001 if ( bUrgent ) {
3002 ppQueueHead = &pSocket->pTxOobPacketListHead;
3003 ppQueueTail = &pSocket->pTxOobPacketListTail;
3004 ppPacket = &pTcp4->pTxOobPacket;
3005 pToken = &pTcp4->TxOobToken;
3006 pTxBytes = &pSocket->TxOobBytes;
3007 }
3008 else {
3009 ppQueueHead = &pSocket->pTxPacketListHead;
3010 ppQueueTail = &pSocket->pTxPacketListTail;
3011 ppPacket = &pTcp4->pTxPacket;
3012 pToken = &pTcp4->TxToken;
3013 pTxBytes = &pSocket->TxBytes;
3014 }
3015
3016 //
3017 // Verify that there is enough room to buffer another
3018 // transmit operation
3019 //
3020 if ( pSocket->MaxTxBuf > *pTxBytes ) {
3021 //
3022 // Attempt to allocate the packet
3023 //
3024 Status = EslSocketPacketAllocate ( &pPacket,
3025 sizeof ( pPacket->Op.Tcp4Tx )
3026 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )
3027 + BufferLength,
3028 DEBUG_TX );
3029 if ( !EFI_ERROR ( Status )) {
3030 //
3031 // Initialize the transmit operation
3032 //
3033 pTxData = &pPacket->Op.Tcp4Tx.TxData;
3034 pTxData->Push = TRUE;
3035 pTxData->Urgent = bUrgent;
3036 pTxData->DataLength = (UINT32) BufferLength;
3037 pTxData->FragmentCount = 1;
3038 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
3039 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];
3040
3041 //
3042 // Copy the data into the buffer
3043 //
3044 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],
3045 pBuffer,
3046 BufferLength );
3047
3048 //
3049 // Synchronize with the socket layer
3050 //
3051 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
3052
3053 //
3054 // Stop transmission after an error
3055 //
3056 if ( !EFI_ERROR ( pSocket->TxError )) {
3057 //
3058 // Display the request
3059 //
3060 DEBUG (( DEBUG_TX,
3061 "Send %d %s bytes from 0x%08x\r\n",
3062 BufferLength,
3063 bUrgent ? L"urgent" : L"normal",
3064 pBuffer ));
3065
3066 //
3067 // Queue the data for transmission
3068 //
3069 pPacket->pNext = NULL;
3070 pPreviousPacket = *ppQueueTail;
3071 if ( NULL == pPreviousPacket ) {
3072 *ppQueueHead = pPacket;
3073 }
3074 else {
3075 pPreviousPacket->pNext = pPacket;
3076 }
3077 *ppQueueTail = pPacket;
3078 DEBUG (( DEBUG_TX,
3079 "0x%08x: Packet on %s transmit list\r\n",
3080 pPacket,
3081 bUrgent ? L"urgent" : L"normal" ));
3082
3083 //
3084 // Account for the buffered data
3085 //
3086 *pTxBytes += BufferLength;
3087 *pDataLength = BufferLength;
3088
3089 //
3090 // Start the transmit engine if it is idle
3091 //
3092 if ( NULL == *ppPacket ) {
3093 EslTcpTxStart4 ( pSocket->pPortList,
3094 pToken,
3095 ppQueueHead,
3096 ppQueueTail,
3097 ppPacket );
3098 }
3099 }
3100 else {
3101 //
3102 // Previous transmit error
3103 // Stop transmission
3104 //
3105 Status = pSocket->TxError;
3106 pSocket->errno = EIO;
3107
3108 //
3109 // Free the packet
3110 //
3111 EslSocketPacketFree ( pPacket, DEBUG_TX );
3112 }
3113
3114 //
3115 // Release the socket layer synchronization
3116 //
3117 RESTORE_TPL ( TplPrevious );
3118 }
3119 else {
3120 //
3121 // Packet allocation failed
3122 //
3123 pSocket->errno = ENOMEM;
3124 }
3125 }
3126 else {
3127 //
3128 // Not enough buffer space available
3129 //
3130 pSocket->errno = EAGAIN;
3131 Status = EFI_NOT_READY;
3132 }
3133 }
3134 }
3135
3136 //
3137 // Return the operation status
3138 //
3139 DBG_EXIT_STATUS ( Status );
3140 return Status;
3141 }
3142
3143
3144 /**
3145 Process the normal data transmit completion
3146
3147 @param Event The normal transmit completion event
3148
3149 @param pPort The DT_PORT structure address
3150
3151 **/
3152 VOID
3153 EslTcpTxComplete4 (
3154 IN EFI_EVENT Event,
3155 IN DT_PORT * pPort
3156 )
3157 {
3158 UINT32 LengthInBytes;
3159 DT_PACKET * pCurrentPacket;
3160 DT_PACKET * pNextPacket;
3161 DT_PACKET * pPacket;
3162 DT_SOCKET * pSocket;
3163 DT_TCP4_CONTEXT * pTcp4;
3164 EFI_STATUS Status;
3165
3166 DBG_ENTER ( );
3167
3168 //
3169 // Locate the active transmit packet
3170 //
3171 pSocket = pPort->pSocket;
3172 pTcp4 = &pPort->Context.Tcp4;
3173 pPacket = pTcp4->pTxPacket;
3174
3175 //
3176 // Mark this packet as complete
3177 //
3178 pTcp4->pTxPacket = NULL;
3179 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
3180 pSocket->TxBytes -= LengthInBytes;
3181
3182 //
3183 // Save any transmit error
3184 //
3185 Status = pTcp4->TxToken.CompletionToken.Status;
3186 if ( EFI_ERROR ( Status )) {
3187 if ( !EFI_ERROR ( pSocket->TxError )) {
3188 pSocket->TxError = Status;
3189 }
3190 DEBUG (( DEBUG_TX | DEBUG_INFO,
3191 "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
3192 pPacket,
3193 Status ));
3194
3195 //
3196 // Empty the normal transmit list
3197 //
3198 pCurrentPacket = pPacket;
3199 pNextPacket = pSocket->pTxPacketListHead;
3200 while ( NULL != pNextPacket ) {
3201 pPacket = pNextPacket;
3202 pNextPacket = pPacket->pNext;
3203 EslSocketPacketFree ( pPacket, DEBUG_TX );
3204 }
3205 pSocket->pTxPacketListHead = NULL;
3206 pSocket->pTxPacketListTail = NULL;
3207 pPacket = pCurrentPacket;
3208 }
3209 else
3210 {
3211 DEBUG (( DEBUG_TX | DEBUG_INFO,
3212 "0x%08x: Packet transmitted %d bytes successfully\r\n",
3213 pPacket,
3214 LengthInBytes ));
3215
3216 //
3217 // Verify the transmit engine is still running
3218 //
3219 if ( !pPort->bCloseNow ) {
3220 //
3221 // Start the next packet transmission
3222 //
3223 EslTcpTxStart4 ( pPort,
3224 &pTcp4->TxToken,
3225 &pSocket->pTxPacketListHead,
3226 &pSocket->pTxPacketListTail,
3227 &pTcp4->pTxPacket );
3228 }
3229 }
3230
3231 //
3232 // Release this packet
3233 //
3234 EslSocketPacketFree ( pPacket, DEBUG_TX );
3235
3236 //
3237 // Finish the close operation if necessary
3238 //
3239 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
3240 //
3241 // Indicate that the transmit is complete
3242 //
3243 EslTcpPortCloseTxDone4 ( pPort );
3244 }
3245 DBG_EXIT ( );
3246 }
3247
3248
3249 /**
3250 Process the urgent data transmit completion
3251
3252 @param Event The urgent transmit completion event
3253
3254 @param pPort The DT_PORT structure address
3255
3256 **/
3257 VOID
3258 EslTcpTxOobComplete4 (
3259 IN EFI_EVENT Event,
3260 IN DT_PORT * pPort
3261 )
3262 {
3263 UINT32 LengthInBytes;
3264 DT_PACKET * pCurrentPacket;
3265 DT_PACKET * pNextPacket;
3266 DT_PACKET * pPacket;
3267 DT_SOCKET * pSocket;
3268 DT_TCP4_CONTEXT * pTcp4;
3269 EFI_STATUS Status;
3270
3271 DBG_ENTER ( );
3272
3273 //
3274 // Locate the active transmit packet
3275 //
3276 pSocket = pPort->pSocket;
3277 pTcp4 = &pPort->Context.Tcp4;
3278 pPacket = pTcp4->pTxOobPacket;
3279
3280 //
3281 // Mark this packet as complete
3282 //
3283 pTcp4->pTxOobPacket = NULL;
3284 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
3285 pSocket->TxOobBytes -= LengthInBytes;
3286
3287 //
3288 // Save any transmit error
3289 //
3290 Status = pTcp4->TxOobToken.CompletionToken.Status;
3291 if ( EFI_ERROR ( Status )) {
3292 if ( !EFI_ERROR ( Status )) {
3293 pSocket->TxError = Status;
3294 }
3295 DEBUG (( DEBUG_TX | DEBUG_INFO,
3296 "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",
3297 pPacket,
3298 Status ));
3299
3300
3301 //
3302 // Empty the OOB transmit list
3303 //
3304 pCurrentPacket = pPacket;
3305 pNextPacket = pSocket->pTxOobPacketListHead;
3306 while ( NULL != pNextPacket ) {
3307 pPacket = pNextPacket;
3308 pNextPacket = pPacket->pNext;
3309 EslSocketPacketFree ( pPacket, DEBUG_TX );
3310 }
3311 pSocket->pTxOobPacketListHead = NULL;
3312 pSocket->pTxOobPacketListTail = NULL;
3313 pPacket = pCurrentPacket;
3314 }
3315 else
3316 {
3317 DEBUG (( DEBUG_TX | DEBUG_INFO,
3318 "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",
3319 pPacket,
3320 LengthInBytes ));
3321
3322 //
3323 // Verify the transmit engine is still running
3324 //
3325 if ( !pPort->bCloseNow ) {
3326 //
3327 // Start the next packet transmission
3328 //
3329 EslTcpTxStart4 ( pPort,
3330 &pTcp4->TxOobToken,
3331 &pSocket->pTxOobPacketListHead,
3332 &pSocket->pTxOobPacketListTail,
3333 &pTcp4->pTxOobPacket );
3334 }
3335 }
3336
3337 //
3338 // Release this packet
3339 //
3340 EslSocketPacketFree ( pPacket, DEBUG_TX );
3341
3342 //
3343 // Finish the close operation if necessary
3344 //
3345 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
3346 //
3347 // Indicate that the transmit is complete
3348 //
3349 EslTcpPortCloseTxDone4 ( pPort );
3350 }
3351 DBG_EXIT ( );
3352 }
3353
3354
3355 /**
3356 Transmit data using a network connection.
3357
3358
3359 @param [in] pPort Address of a DT_PORT structure
3360 @param [in] pToken Address of either the OOB or normal transmit token
3361 @param [in] ppQueueHead Transmit queue head address
3362 @param [in] ppQueueTail Transmit queue tail address
3363 @param [in] ppPacket Active transmit packet address
3364
3365 **/
3366 VOID
3367 EslTcpTxStart4 (
3368 IN DT_PORT * pPort,
3369 IN EFI_TCP4_IO_TOKEN * pToken,
3370 IN DT_PACKET ** ppQueueHead,
3371 IN DT_PACKET ** ppQueueTail,
3372 IN DT_PACKET ** ppPacket
3373 )
3374 {
3375 DT_PACKET * pNextPacket;
3376 DT_PACKET * pPacket;
3377 DT_SOCKET * pSocket;
3378 EFI_TCP4_PROTOCOL * pTcp4Protocol;
3379 EFI_STATUS Status;
3380
3381 DBG_ENTER ( );
3382
3383 //
3384 // Assume success
3385 //
3386 Status = EFI_SUCCESS;
3387
3388 //
3389 // Get the packet from the queue head
3390 //
3391 pPacket = *ppQueueHead;
3392 if ( NULL != pPacket ) {
3393 //
3394 // Remove the packet from the queue
3395 //
3396 pNextPacket = pPacket->pNext;
3397 *ppQueueHead = pNextPacket;
3398 if ( NULL == pNextPacket ) {
3399 *ppQueueTail = NULL;
3400 }
3401
3402 //
3403 // Set the packet as active
3404 //
3405 *ppPacket = pPacket;
3406
3407 //
3408 // Start the transmit operation
3409 //
3410 pTcp4Protocol = pPort->Context.Tcp4.pProtocol;
3411 pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;
3412 Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );
3413 if ( EFI_ERROR ( Status )) {
3414 pSocket = pPort->pSocket;
3415 if ( EFI_SUCCESS == pSocket->TxError ) {
3416 pSocket->TxError = Status;
3417 }
3418 }
3419 }
3420
3421 DBG_EXIT ( );
3422 }