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