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