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