]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Tcp4.c
Add Socket Libraries.
[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 switch ( Status ) {
2452 default:
2453 pSocket->errno = EIO;
2454 break;
2455
2456 case EFI_CONNECTION_FIN:
2457 pSocket->errno = ESHUTDOWN;
2458 break;
2459
2460 case EFI_CONNECTION_REFUSED:
2461 pSocket->errno = ECONNREFUSED;
2462 break;
2463
2464 case EFI_CONNECTION_RESET:
2465 pSocket->errno = ECONNRESET;
2466 break;
2467
2468 case EFI_HOST_UNREACHABLE:
2469 pSocket->errno = EHOSTUNREACH;
2470 break;
2471
2472 case EFI_NETWORK_UNREACHABLE:
2473 pSocket->errno = ENETUNREACH;
2474 break;
2475
2476 case EFI_PORT_UNREACHABLE:
2477 pSocket->errno = EPROTONOSUPPORT;
2478 break;
2479
2480 case EFI_PROTOCOL_UNREACHABLE:
2481 pSocket->errno = ENOPROTOOPT;
2482 break;
2483 }
2484 pSocket->RxError = EFI_SUCCESS;
2485 }
2486 else {
2487 Status = EFI_NOT_READY;
2488 pSocket->errno = EAGAIN;
2489 }
2490 }
2491 }
2492 }
2493
2494 //
2495 // Return the operation status
2496 //
2497 DBG_EXIT_STATUS ( Status );
2498 return Status;
2499 }
2500
2501
2502 /**
2503 Cancel the receive operations
2504
2505 @param [in] pSocket Address of a DT_SOCKET structure
2506
2507 @retval EFI_SUCCESS - The cancel was successful
2508
2509 **/
2510 EFI_STATUS
2511 EslTcpRxCancel4 (
2512 IN DT_SOCKET * pSocket
2513 )
2514 {
2515 DT_PACKET * pPacket;
2516 DT_PORT * pPort;
2517 DT_TCP4_CONTEXT * pTcp4;
2518 EFI_TCP4_PROTOCOL * pTcp4Protocol;
2519 EFI_STATUS Status;
2520
2521 DBG_ENTER ( );
2522
2523 //
2524 // Assume failure
2525 //
2526 Status = EFI_NOT_FOUND;
2527
2528 //
2529 // Locate the port
2530 //
2531 pPort = pSocket->pPortList;
2532 if ( NULL != pPort ) {
2533 //
2534 // Determine if a receive is pending
2535 //
2536 pTcp4 = &pPort->Context.Tcp4;
2537 pPacket = pTcp4->pReceivePending;
2538 if ( NULL != pPacket ) {
2539 //
2540 // Attempt to cancel the receive operation
2541 //
2542 pTcp4Protocol = pTcp4->pProtocol;
2543 Status = pTcp4Protocol->Cancel ( pTcp4Protocol,
2544 &pTcp4->RxToken.CompletionToken );
2545 if ( EFI_NOT_FOUND == Status ) {
2546 //
2547 // The receive is complete
2548 //
2549 Status = EFI_SUCCESS;
2550 }
2551 }
2552 }
2553
2554 //
2555 // Return the operation status
2556 //
2557 DBG_EXIT_STATUS ( Status );
2558 return Status;
2559 }
2560
2561
2562 /**
2563 Process the receive completion
2564
2565 Buffer the data that was just received.
2566
2567 @param Event The receive completion event
2568
2569 @param pPort The DT_PORT structure address
2570
2571 **/
2572 VOID
2573 EslTcpRxComplete4 (
2574 IN EFI_EVENT Event,
2575 IN DT_PORT * pPort
2576 )
2577 {
2578 BOOLEAN bUrgent;
2579 size_t LengthInBytes;
2580 DT_PACKET * pPacket;
2581 DT_PACKET * pPrevious;
2582 DT_SOCKET * pSocket;
2583 DT_TCP4_CONTEXT * pTcp4;
2584 EFI_STATUS Status;
2585
2586 DBG_ENTER ( );
2587
2588 //
2589 // Mark this receive complete
2590 //
2591 pTcp4 = &pPort->Context.Tcp4;
2592 pPacket = pTcp4->pReceivePending;
2593 pTcp4->pReceivePending = NULL;
2594
2595 //
2596 // Determine if this receive was successful
2597 //
2598 pSocket = pPort->pSocket;
2599 Status = pTcp4->RxToken.CompletionToken.Status;
2600 if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
2601 //
2602 // Set the buffer size and address
2603 //
2604 pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;
2605 LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;
2606 pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;
2607 pPacket->pNext = NULL;
2608
2609 //
2610 // Queue this packet
2611 //
2612 bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;
2613 if ( bUrgent ) {
2614 //
2615 // Add packet to the urgent list
2616 //
2617 pPrevious = pSocket->pRxOobPacketListTail;
2618 if ( NULL == pPrevious ) {
2619 pSocket->pRxOobPacketListHead = pPacket;
2620 }
2621 else {
2622 pPrevious->pNext = pPacket;
2623 }
2624 pSocket->pRxOobPacketListTail = pPacket;
2625
2626 //
2627 // Account for the urgent data
2628 //
2629 pSocket->RxOobBytes += LengthInBytes;
2630 }
2631 else {
2632 //
2633 // Add packet to the normal list
2634 //
2635 pPrevious = pSocket->pRxPacketListTail;
2636 if ( NULL == pPrevious ) {
2637 pSocket->pRxPacketListHead = pPacket;
2638 }
2639 else {
2640 pPrevious->pNext = pPacket;
2641 }
2642 pSocket->pRxPacketListTail = pPacket;
2643
2644 //
2645 // Account for the normal data
2646 //
2647 pSocket->RxBytes += LengthInBytes;
2648 }
2649
2650 //
2651 // Log the received data
2652 //
2653 DEBUG (( DEBUG_RX | DEBUG_INFO,
2654 "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",
2655 pPacket,
2656 pPort,
2657 LengthInBytes,
2658 bUrgent ? L"urgent" : L"normal" ));
2659
2660 //
2661 // Attempt to restart this receive operation
2662 //
2663 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
2664 EslTcpRxStart4 ( pPort );
2665 }
2666 else {
2667 DEBUG (( DEBUG_RX,
2668 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
2669 pPort,
2670 pSocket->RxBytes ));
2671 }
2672 }
2673 else
2674 {
2675 DEBUG (( DEBUG_RX | DEBUG_INFO,
2676 "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
2677 pPacket,
2678 pPort,
2679 Status ));
2680
2681 //
2682 // Receive error, free the packet save the error
2683 //
2684 EslSocketPacketFree ( pPacket, DEBUG_RX );
2685 if ( !EFI_ERROR ( pSocket->RxError )) {
2686 pSocket->RxError = Status;
2687 }
2688
2689 //
2690 // Update the port state
2691 //
2692 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
2693 EslTcpPortCloseRxDone4 ( pPort );
2694 }
2695 else {
2696 if ( EFI_ERROR ( Status )) {
2697 pPort->State = PORT_STATE_RX_ERROR;
2698 }
2699 }
2700 }
2701
2702 DBG_EXIT ( );
2703 }
2704
2705
2706 /**
2707 Start a receive operation
2708
2709 @param [in] pPort Address of the DT_PORT structure.
2710
2711 **/
2712 VOID
2713 EslTcpRxStart4 (
2714 IN DT_PORT * pPort
2715 )
2716 {
2717 size_t LengthInBytes;
2718 DT_PACKET * pPacket;
2719 DT_SOCKET * pSocket;
2720 DT_TCP4_CONTEXT * pTcp4;
2721 EFI_TCP4_PROTOCOL * pTcp4Protocol;
2722 EFI_STATUS Status;
2723
2724 DBG_ENTER ( );
2725
2726 //
2727 // Determine if a receive is already pending
2728 //
2729 Status = EFI_SUCCESS;
2730 pPacket = NULL;
2731 pSocket = pPort->pSocket;
2732 pTcp4 = &pPort->Context.Tcp4;
2733 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
2734 if (( NULL == pTcp4->pReceivePending )
2735 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
2736 //
2737 // Determine if there are any free packets
2738 //
2739 pPacket = pSocket->pRxFree;
2740 LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );
2741 if ( NULL != pPacket ) {
2742 //
2743 // Remove this packet from the free list
2744 //
2745 pSocket->pRxFree = pPacket->pNext;
2746 DEBUG (( DEBUG_RX,
2747 "0x%08x: Port removed packet 0x%08x from free list\r\n",
2748 pPort,
2749 pPacket ));
2750 }
2751 else {
2752 //
2753 // Allocate a packet structure
2754 //
2755 Status = EslSocketPacketAllocate ( &pPacket,
2756 sizeof ( pPacket->Op.Tcp4Rx ),
2757 DEBUG_RX );
2758 if ( EFI_ERROR ( Status )) {
2759 pPacket = NULL;
2760 DEBUG (( DEBUG_ERROR | DEBUG_RX,
2761 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
2762 pPort,
2763 Status ));
2764 }
2765 }
2766
2767 //
2768 // Determine if a packet is available
2769 //
2770 if ( NULL != pPacket ) {
2771 //
2772 // Initialize the buffer for receive
2773 //
2774 pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;
2775 pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;
2776 pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;
2777 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;
2778 pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];
2779 pTcp4->pReceivePending = pPacket;
2780
2781 //
2782 // Start the receive on the packet
2783 //
2784 pTcp4Protocol = pTcp4->pProtocol;
2785 Status = pTcp4Protocol->Receive ( pTcp4Protocol,
2786 &pTcp4->RxToken );
2787 if ( !EFI_ERROR ( Status )) {
2788 DEBUG (( DEBUG_RX | DEBUG_INFO,
2789 "0x%08x: Packet receive pending on port 0x%08x\r\n",
2790 pPacket,
2791 pPort ));
2792 }
2793 else {
2794 DEBUG (( DEBUG_RX | DEBUG_INFO,
2795 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
2796 pPort,
2797 Status ));
2798 pTcp4->pReceivePending = NULL;
2799 if ( !EFI_ERROR ( pSocket->RxError )) {
2800 //
2801 // Save the error status
2802 //
2803 pSocket->RxError = Status;
2804 }
2805 }
2806 }
2807 }
2808 }
2809
2810 DBG_EXIT ( );
2811 }
2812
2813
2814 /**
2815 Shutdown the TCP4 service.
2816
2817 This routine undoes the work performed by ::TcpInitialize4.
2818
2819 @param [in] pService DT_SERVICE structure address
2820
2821 **/
2822 VOID
2823 EFIAPI
2824 EslTcpShutdown4 (
2825 IN DT_SERVICE * pService
2826 )
2827 {
2828 DT_LAYER * pLayer;
2829 DT_PORT * pPort;
2830 DT_SERVICE * pPreviousService;
2831
2832 DBG_ENTER ( );
2833
2834 //
2835 // Verify the socket layer synchronization
2836 //
2837 VERIFY_TPL ( TPL_SOCKETS );
2838
2839 //
2840 // Walk the list of ports
2841 //
2842 do {
2843 pPort = pService->pPortList;
2844 if ( NULL != pPort ) {
2845 //
2846 // Remove the port from the port list
2847 //
2848 pService->pPortList = pPort->pLinkService;
2849
2850 //
2851 // Close the port
2852 // TODO: Fix this
2853 //
2854 // pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );
2855 }
2856 } while ( NULL != pPort );
2857
2858 //
2859 // Remove the service from the service list
2860 //
2861 pLayer = &mEslLayer;
2862 pPreviousService = pLayer->pTcp4List;
2863 if ( pService == pPreviousService ) {
2864 //
2865 // Remove the service from the beginning of the list
2866 //
2867 pLayer->pTcp4List = pService->pNext;
2868 }
2869 else {
2870 //
2871 // Remove the service from the middle of the list
2872 //
2873 while ( NULL != pPreviousService ) {
2874 if ( pService == pPreviousService->pNext ) {
2875 pPreviousService->pNext = pService->pNext;
2876 break;
2877 }
2878 }
2879 }
2880
2881 DBG_EXIT ( );
2882 }
2883
2884
2885 /**
2886 Determine if the socket is configured.
2887
2888
2889 @param [in] pSocket Address of a DT_SOCKET structure
2890
2891 @retval EFI_SUCCESS - The port is connected
2892 @retval EFI_NOT_STARTED - The port is not connected
2893
2894 **/
2895 EFI_STATUS
2896 EslTcpSocketIsConfigured4 (
2897 IN DT_SOCKET * pSocket
2898 )
2899 {
2900 EFI_STATUS Status;
2901
2902 DBG_ENTER ( );
2903
2904 //
2905 // Determine the socket configuration status
2906 //
2907 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
2908
2909 //
2910 // Return the port connected state.
2911 //
2912 DBG_EXIT_STATUS ( Status );
2913 return Status;
2914 }
2915
2916
2917 /**
2918 Buffer data for transmission over a network connection.
2919
2920 This routine is called by the socket layer API to buffer
2921 data for transmission. When necessary, this routine will
2922 start the transmit engine that performs the data transmission
2923 on the network connection.
2924
2925 The transmit engine uses two queues, one for urgent (out-of-band)
2926 data and the other for normal data. The urgent data is provided
2927 to TCP as soon as it is available, allowing the TCP layer to
2928 schedule transmission of the urgent data between packets of normal
2929 data.
2930
2931 Transmission errors are returned during the next transmission or
2932 during the close operation. Only buffering errors are returned
2933 during the current transmission attempt.
2934
2935 @param [in] pSocket Address of a DT_SOCKET structure
2936
2937 @param [in] Flags Message control flags
2938
2939 @param [in] BufferLength Length of the the buffer
2940
2941 @param [in] pBuffer Address of a buffer to receive the data.
2942
2943 @param [in] pDataLength Number of received data bytes in the buffer.
2944
2945 @retval EFI_SUCCESS - Socket data successfully buffered
2946
2947 **/
2948 EFI_STATUS
2949 EslTcpTxBuffer4 (
2950 IN DT_SOCKET * pSocket,
2951 IN int Flags,
2952 IN size_t BufferLength,
2953 IN CONST UINT8 * pBuffer,
2954 OUT size_t * pDataLength
2955 )
2956 {
2957 BOOLEAN bUrgent;
2958 DT_PACKET * pPacket;
2959 DT_PACKET * pPreviousPacket;
2960 DT_PACKET ** ppPacket;
2961 DT_PACKET ** ppQueueHead;
2962 DT_PACKET ** ppQueueTail;
2963 DT_PORT * pPort;
2964 DT_TCP4_CONTEXT * pTcp4;
2965 EFI_TCP4_IO_TOKEN * pToken;
2966 size_t * pTxBytes;
2967 EFI_TCP4_TRANSMIT_DATA * pTxData;
2968 EFI_STATUS Status;
2969 EFI_TPL TplPrevious;
2970
2971 DBG_ENTER ( );
2972
2973 //
2974 // Assume failure
2975 //
2976 Status = EFI_UNSUPPORTED;
2977 pSocket->errno = ENOTCONN;
2978 * pDataLength = 0;
2979
2980 //
2981 // Verify that the socket is connected
2982 //
2983 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
2984 //
2985 // Locate the port
2986 //
2987 pPort = pSocket->pPortList;
2988 if ( NULL != pPort ) {
2989 //
2990 // Determine the queue head
2991 //
2992 pTcp4 = &pPort->Context.Tcp4;
2993 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
2994 if ( bUrgent ) {
2995 ppQueueHead = &pSocket->pTxOobPacketListHead;
2996 ppQueueTail = &pSocket->pTxOobPacketListTail;
2997 ppPacket = &pTcp4->pTxOobPacket;
2998 pToken = &pTcp4->TxOobToken;
2999 pTxBytes = &pSocket->TxOobBytes;
3000 }
3001 else {
3002 ppQueueHead = &pSocket->pTxPacketListHead;
3003 ppQueueTail = &pSocket->pTxPacketListTail;
3004 ppPacket = &pTcp4->pTxPacket;
3005 pToken = &pTcp4->TxToken;
3006 pTxBytes = &pSocket->TxBytes;
3007 }
3008
3009 //
3010 // Verify that there is enough room to buffer another
3011 // transmit operation
3012 //
3013 if ( pSocket->MaxTxBuf > *pTxBytes ) {
3014 //
3015 // Attempt to allocate the packet
3016 //
3017 Status = EslSocketPacketAllocate ( &pPacket,
3018 sizeof ( pPacket->Op.Tcp4Tx )
3019 - sizeof ( pPacket->Op.Tcp4Tx.Buffer )
3020 + BufferLength,
3021 DEBUG_TX );
3022 if ( !EFI_ERROR ( Status )) {
3023 //
3024 // Initialize the transmit operation
3025 //
3026 pTxData = &pPacket->Op.Tcp4Tx.TxData;
3027 pTxData->Push = TRUE;
3028 pTxData->Urgent = bUrgent;
3029 pTxData->DataLength = (UINT32) BufferLength;
3030 pTxData->FragmentCount = 1;
3031 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
3032 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];
3033
3034 //
3035 // Copy the data into the buffer
3036 //
3037 CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],
3038 pBuffer,
3039 BufferLength );
3040
3041 //
3042 // Synchronize with the socket layer
3043 //
3044 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
3045
3046 //
3047 // Stop transmission after an error
3048 //
3049 if ( !EFI_ERROR ( pSocket->TxError )) {
3050 //
3051 // Display the request
3052 //
3053 DEBUG (( DEBUG_TX,
3054 "Send %d %s bytes from 0x%08x\r\n",
3055 BufferLength,
3056 bUrgent ? L"urgent" : L"normal",
3057 pBuffer ));
3058
3059 //
3060 // Queue the data for transmission
3061 //
3062 pPacket->pNext = NULL;
3063 pPreviousPacket = *ppQueueTail;
3064 if ( NULL == pPreviousPacket ) {
3065 *ppQueueHead = pPacket;
3066 }
3067 else {
3068 pPreviousPacket->pNext = pPacket;
3069 }
3070 *ppQueueTail = pPacket;
3071 DEBUG (( DEBUG_TX,
3072 "0x%08x: Packet on %s transmit list\r\n",
3073 pPacket,
3074 bUrgent ? L"urgent" : L"normal" ));
3075
3076 //
3077 // Account for the buffered data
3078 //
3079 *pTxBytes += BufferLength;
3080 *pDataLength = BufferLength;
3081
3082 //
3083 // Start the transmit engine if it is idle
3084 //
3085 if ( NULL == *ppPacket ) {
3086 EslTcpTxStart4 ( pSocket->pPortList,
3087 pToken,
3088 ppQueueHead,
3089 ppQueueTail,
3090 ppPacket );
3091 }
3092 }
3093 else {
3094 //
3095 // Previous transmit error
3096 // Stop transmission
3097 //
3098 Status = pSocket->TxError;
3099 pSocket->errno = EIO;
3100
3101 //
3102 // Free the packet
3103 //
3104 EslSocketPacketFree ( pPacket, DEBUG_TX );
3105 }
3106
3107 //
3108 // Release the socket layer synchronization
3109 //
3110 RESTORE_TPL ( TplPrevious );
3111 }
3112 else {
3113 //
3114 // Packet allocation failed
3115 //
3116 pSocket->errno = ENOMEM;
3117 }
3118 }
3119 else {
3120 //
3121 // Not enough buffer space available
3122 //
3123 pSocket->errno = EAGAIN;
3124 Status = EFI_NOT_READY;
3125 }
3126 }
3127 }
3128
3129 //
3130 // Return the operation status
3131 //
3132 DBG_EXIT_STATUS ( Status );
3133 return Status;
3134 }
3135
3136
3137 /**
3138 Process the normal data transmit completion
3139
3140 @param Event The normal transmit completion event
3141
3142 @param pPort The DT_PORT structure address
3143
3144 **/
3145 VOID
3146 EslTcpTxComplete4 (
3147 IN EFI_EVENT Event,
3148 IN DT_PORT * pPort
3149 )
3150 {
3151 UINT32 LengthInBytes;
3152 DT_PACKET * pCurrentPacket;
3153 DT_PACKET * pNextPacket;
3154 DT_PACKET * pPacket;
3155 DT_SOCKET * pSocket;
3156 DT_TCP4_CONTEXT * pTcp4;
3157 EFI_STATUS Status;
3158
3159 DBG_ENTER ( );
3160
3161 //
3162 // Locate the active transmit packet
3163 //
3164 pSocket = pPort->pSocket;
3165 pTcp4 = &pPort->Context.Tcp4;
3166 pPacket = pTcp4->pTxPacket;
3167
3168 //
3169 // Mark this packet as complete
3170 //
3171 pTcp4->pTxPacket = NULL;
3172 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
3173 pSocket->TxBytes -= LengthInBytes;
3174
3175 //
3176 // Save any transmit error
3177 //
3178 Status = pTcp4->TxToken.CompletionToken.Status;
3179 if ( EFI_ERROR ( Status )) {
3180 if ( !EFI_ERROR ( pSocket->TxError )) {
3181 pSocket->TxError = Status;
3182 }
3183 DEBUG (( DEBUG_TX | DEBUG_INFO,
3184 "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
3185 pPacket,
3186 Status ));
3187
3188 //
3189 // Empty the normal transmit list
3190 //
3191 pCurrentPacket = pPacket;
3192 pNextPacket = pSocket->pTxPacketListHead;
3193 while ( NULL != pNextPacket ) {
3194 pPacket = pNextPacket;
3195 pNextPacket = pPacket->pNext;
3196 EslSocketPacketFree ( pPacket, DEBUG_TX );
3197 }
3198 pSocket->pTxPacketListHead = NULL;
3199 pSocket->pTxPacketListTail = NULL;
3200 pPacket = pCurrentPacket;
3201 }
3202 else
3203 {
3204 DEBUG (( DEBUG_TX | DEBUG_INFO,
3205 "0x%08x: Packet transmitted %d bytes successfully\r\n",
3206 pPacket,
3207 LengthInBytes ));
3208
3209 //
3210 // Verify the transmit engine is still running
3211 //
3212 if ( !pPort->bCloseNow ) {
3213 //
3214 // Start the next packet transmission
3215 //
3216 EslTcpTxStart4 ( pPort,
3217 &pTcp4->TxToken,
3218 &pSocket->pTxPacketListHead,
3219 &pSocket->pTxPacketListTail,
3220 &pTcp4->pTxPacket );
3221 }
3222 }
3223
3224 //
3225 // Release this packet
3226 //
3227 EslSocketPacketFree ( pPacket, DEBUG_TX );
3228
3229 //
3230 // Finish the close operation if necessary
3231 //
3232 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
3233 //
3234 // Indicate that the transmit is complete
3235 //
3236 EslTcpPortCloseTxDone4 ( pPort );
3237 }
3238 DBG_EXIT ( );
3239 }
3240
3241
3242 /**
3243 Process the urgent data transmit completion
3244
3245 @param Event The urgent transmit completion event
3246
3247 @param pPort The DT_PORT structure address
3248
3249 **/
3250 VOID
3251 EslTcpTxOobComplete4 (
3252 IN EFI_EVENT Event,
3253 IN DT_PORT * pPort
3254 )
3255 {
3256 UINT32 LengthInBytes;
3257 DT_PACKET * pCurrentPacket;
3258 DT_PACKET * pNextPacket;
3259 DT_PACKET * pPacket;
3260 DT_SOCKET * pSocket;
3261 DT_TCP4_CONTEXT * pTcp4;
3262 EFI_STATUS Status;
3263
3264 DBG_ENTER ( );
3265
3266 //
3267 // Locate the active transmit packet
3268 //
3269 pSocket = pPort->pSocket;
3270 pTcp4 = &pPort->Context.Tcp4;
3271 pPacket = pTcp4->pTxOobPacket;
3272
3273 //
3274 // Mark this packet as complete
3275 //
3276 pTcp4->pTxOobPacket = NULL;
3277 LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;
3278 pSocket->TxOobBytes -= LengthInBytes;
3279
3280 //
3281 // Save any transmit error
3282 //
3283 Status = pTcp4->TxOobToken.CompletionToken.Status;
3284 if ( EFI_ERROR ( Status )) {
3285 if ( !EFI_ERROR ( Status )) {
3286 pSocket->TxError = Status;
3287 }
3288 DEBUG (( DEBUG_TX | DEBUG_INFO,
3289 "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",
3290 pPacket,
3291 Status ));
3292
3293
3294 //
3295 // Empty the OOB transmit list
3296 //
3297 pCurrentPacket = pPacket;
3298 pNextPacket = pSocket->pTxOobPacketListHead;
3299 while ( NULL != pNextPacket ) {
3300 pPacket = pNextPacket;
3301 pNextPacket = pPacket->pNext;
3302 EslSocketPacketFree ( pPacket, DEBUG_TX );
3303 }
3304 pSocket->pTxOobPacketListHead = NULL;
3305 pSocket->pTxOobPacketListTail = NULL;
3306 pPacket = pCurrentPacket;
3307 }
3308 else
3309 {
3310 DEBUG (( DEBUG_TX | DEBUG_INFO,
3311 "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",
3312 pPacket,
3313 LengthInBytes ));
3314
3315 //
3316 // Verify the transmit engine is still running
3317 //
3318 if ( !pPort->bCloseNow ) {
3319 //
3320 // Start the next packet transmission
3321 //
3322 EslTcpTxStart4 ( pPort,
3323 &pTcp4->TxOobToken,
3324 &pSocket->pTxOobPacketListHead,
3325 &pSocket->pTxOobPacketListTail,
3326 &pTcp4->pTxOobPacket );
3327 }
3328 }
3329
3330 //
3331 // Release this packet
3332 //
3333 EslSocketPacketFree ( pPacket, DEBUG_TX );
3334
3335 //
3336 // Finish the close operation if necessary
3337 //
3338 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
3339 //
3340 // Indicate that the transmit is complete
3341 //
3342 EslTcpPortCloseTxDone4 ( pPort );
3343 }
3344 DBG_EXIT ( );
3345 }
3346
3347
3348 /**
3349 Transmit data using a network connection.
3350
3351
3352 @param [in] pPort Address of a DT_PORT structure
3353 @param [in] pToken Address of either the OOB or normal transmit token
3354 @param [in] ppQueueHead Transmit queue head address
3355 @param [in] ppQueueTail Transmit queue tail address
3356 @param [in] ppPacket Active transmit packet address
3357
3358 **/
3359 VOID
3360 EslTcpTxStart4 (
3361 IN DT_PORT * pPort,
3362 IN EFI_TCP4_IO_TOKEN * pToken,
3363 IN DT_PACKET ** ppQueueHead,
3364 IN DT_PACKET ** ppQueueTail,
3365 IN DT_PACKET ** ppPacket
3366 )
3367 {
3368 DT_PACKET * pNextPacket;
3369 DT_PACKET * pPacket;
3370 DT_SOCKET * pSocket;
3371 EFI_TCP4_PROTOCOL * pTcp4Protocol;
3372 EFI_STATUS Status;
3373
3374 DBG_ENTER ( );
3375
3376 //
3377 // Assume success
3378 //
3379 Status = EFI_SUCCESS;
3380
3381 //
3382 // Get the packet from the queue head
3383 //
3384 pPacket = *ppQueueHead;
3385 if ( NULL != pPacket ) {
3386 //
3387 // Remove the packet from the queue
3388 //
3389 pNextPacket = pPacket->pNext;
3390 *ppQueueHead = pNextPacket;
3391 if ( NULL == pNextPacket ) {
3392 *ppQueueTail = NULL;
3393 }
3394
3395 //
3396 // Set the packet as active
3397 //
3398 *ppPacket = pPacket;
3399
3400 //
3401 // Start the transmit operation
3402 //
3403 pTcp4Protocol = pPort->Context.Tcp4.pProtocol;
3404 pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;
3405 Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );
3406 if ( EFI_ERROR ( Status )) {
3407 pSocket = pPort->pSocket;
3408 if ( EFI_SUCCESS == pSocket->TxError ) {
3409 pSocket->TxError = Status;
3410 }
3411 }
3412 }
3413
3414 DBG_EXIT ( );
3415 }