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