1 /** @file 2 Implement the TCP6 driver support for the socket layer. 3 4 Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed and made available 6 under the terms and conditions of the BSD License which accompanies this 7 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_PORT * pNewPort; 875 ESL_SOCKET * pNewSocket; 876 ESL_SOCKET * pSocket; 877 ESL_TCP6_CONTEXT * pTcp6; 878 EFI_TCP6_PROTOCOL * pTcp6Protocol; 879 EFI_STATUS Status; 880 EFI_HANDLE TcpPortHandle; 881 EFI_STATUS TempStatus; 882 883 DBG_ENTER ( ); 884 VERIFY_AT_TPL ( TPL_SOCKETS ); 885 886 // 887 // Assume success 888 // 889 Status = EFI_SUCCESS; 890 891 // 892 // Determine if this connection fits into the connection FIFO 893 // 894 pSocket = pPort->pSocket; 895 TcpPortHandle = pPort->Context.Tcp6.ListenToken.NewChildHandle; 896 if (( SOCKET_STATE_LISTENING == pSocket->State ) 897 && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) { 898 // 899 // Allocate a socket for this connection 900 // 901 ChildHandle = NULL; 902 Status = EslSocketAllocate ( &ChildHandle, 903 DEBUG_CONNECTION, 904 &pNewSocket ); 905 if ( !EFI_ERROR ( Status )) { 906 // 907 // Clone the socket parameters 908 // 909 pNewSocket->pApi = pSocket->pApi; 910 pNewSocket->Domain = pSocket->Domain; 911 pNewSocket->Protocol = pSocket->Protocol; 912 pNewSocket->Type = pSocket->Type; 913 914 // 915 // Build the local address 916 // 917 pTcp6 = &pPort->Context.Tcp6; 918 LocalAddress.sin6_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength; 919 LocalAddress.sin6_family = AF_INET6; 920 LocalAddress.sin6_port = 0; 921 CopyMem ( &LocalAddress.sin6_addr.__u6_addr.__u6_addr8 [ 0 ], 922 &pTcp6->ConfigData.AccessPoint.StationAddress.Addr [ 0 ], 923 sizeof ( pTcp6->ConfigData.AccessPoint.StationAddress.Addr )); 924 925 // 926 // Allocate a port for this connection 927 // Note in this instance Configure may not be called with NULL! 928 // 929 Status = EslSocketPortAllocate ( pNewSocket, 930 pPort->pService, 931 TcpPortHandle, 932 (struct sockaddr *)&LocalAddress, 933 FALSE, 934 DEBUG_CONNECTION, 935 &pNewPort ); 936 if ( !EFI_ERROR ( Status )) { 937 // 938 // Restart the listen operation on the port 939 // 940 pTcp6Protocol = pPort->pProtocol.TCPv6; 941 Status = pTcp6Protocol->Accept ( pTcp6Protocol, 942 &pTcp6->ListenToken ); 943 944 // 945 // Close the TCP port using SocketClose 946 // 947 TcpPortHandle = NULL; 948 pTcp6 = &pNewPort->Context.Tcp6; 949 950 // 951 // Check for an accept call error 952 // 953 if ( !EFI_ERROR ( Status )) { 954 // 955 // Get the port configuration 956 // 957 pNewPort->bConfigured = TRUE; 958 pConfigData = &pTcp6->ConfigData; 959 pConfigData->ControlOption = &pTcp6->Option; 960 pTcp6Protocol = pNewPort->pProtocol.TCPv6; 961 Status = pTcp6Protocol->GetModeData ( pTcp6Protocol, 962 NULL, 963 pConfigData, 964 NULL, 965 NULL, 966 NULL ); 967 if ( !EFI_ERROR ( Status )) { 968 // 969 // Add the new socket to the connection FIFO 970 // 971 if ( NULL == pSocket->pFifoTail ) { 972 // 973 // First connection 974 // 975 pSocket->pFifoHead = pNewSocket; 976 } 977 else { 978 // 979 // Add to end of list. 980 // 981 pSocket->pFifoTail->pNextConnection = pNewSocket; 982 } 983 pSocket->pFifoTail = pNewSocket; 984 pSocket->FifoDepth += 1; 985 986 // 987 // Update the socket state 988 // 989 pNewSocket->State = SOCKET_STATE_IN_FIFO; 990 991 // 992 // Log the connection 993 // 994 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO, 995 "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", 996 pNewSocket, 997 pConfigData->AccessPoint.StationAddress.Addr[0], 998 pConfigData->AccessPoint.StationAddress.Addr[1], 999 pConfigData->AccessPoint.StationAddress.Addr[2], 1000 pConfigData->AccessPoint.StationAddress.Addr[3], 1001 pConfigData->AccessPoint.StationAddress.Addr[4], 1002 pConfigData->AccessPoint.StationAddress.Addr[5], 1003 pConfigData->AccessPoint.StationAddress.Addr[6], 1004 pConfigData->AccessPoint.StationAddress.Addr[7], 1005 pConfigData->AccessPoint.StationAddress.Addr[8], 1006 pConfigData->AccessPoint.StationAddress.Addr[9], 1007 pConfigData->AccessPoint.StationAddress.Addr[10], 1008 pConfigData->AccessPoint.StationAddress.Addr[11], 1009 pConfigData->AccessPoint.StationAddress.Addr[12], 1010 pConfigData->AccessPoint.StationAddress.Addr[13], 1011 pConfigData->AccessPoint.StationAddress.Addr[14], 1012 pConfigData->AccessPoint.StationAddress.Addr[15], 1013 pConfigData->AccessPoint.StationPort, 1014 pConfigData->AccessPoint.RemoteAddress.Addr[0], 1015 pConfigData->AccessPoint.RemoteAddress.Addr[1], 1016 pConfigData->AccessPoint.RemoteAddress.Addr[2], 1017 pConfigData->AccessPoint.RemoteAddress.Addr[3], 1018 pConfigData->AccessPoint.RemoteAddress.Addr[4], 1019 pConfigData->AccessPoint.RemoteAddress.Addr[5], 1020 pConfigData->AccessPoint.RemoteAddress.Addr[6], 1021 pConfigData->AccessPoint.RemoteAddress.Addr[7], 1022 pConfigData->AccessPoint.RemoteAddress.Addr[8], 1023 pConfigData->AccessPoint.RemoteAddress.Addr[9], 1024 pConfigData->AccessPoint.RemoteAddress.Addr[10], 1025 pConfigData->AccessPoint.RemoteAddress.Addr[11], 1026 pConfigData->AccessPoint.RemoteAddress.Addr[12], 1027 pConfigData->AccessPoint.RemoteAddress.Addr[13], 1028 pConfigData->AccessPoint.RemoteAddress.Addr[14], 1029 pConfigData->AccessPoint.RemoteAddress.Addr[15], 1030 pConfigData->AccessPoint.RemotePort )); 1031 DEBUG (( DEBUG_CONNECTION | DEBUG_INFO, 1032 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n", 1033 pSocket, 1034 pNewSocket, 1035 pSocket->FifoDepth )); 1036 1037 // 1038 // Start the receive operation 1039 // 1040 EslSocketRxStart ( pNewPort ); 1041 } 1042 else { 1043 DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO, 1044 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n", 1045 pNewPort, 1046 Status )); 1047 } 1048 } 1049 else { 1050 // 1051 // The listen failed on this port 1052 // 1053 DEBUG (( DEBUG_LISTEN | DEBUG_INFO, 1054 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n", 1055 pPort, 1056 Status )); 1057 1058 // 1059 // Close the listening port 1060 // 1061 EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN ); 1062 } 1063 } 1064 1065 // 1066 // Done with the socket if necessary 1067 // 1068 if ( EFI_ERROR ( Status )) { 1069 TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol, 1070 TRUE, 1071 &pSocket->errno ); 1072 ASSERT ( EFI_SUCCESS == TempStatus ); 1073 } 1074 } 1075 } 1076 else { 1077 DEBUG (( DEBUG_CONNECTION, 1078 "0x%08x: Socket FIFO full, connection refused\r\n", 1079 pSocket )); 1080 1081 // 1082 // The FIFO is full or the socket is in the wrong state 1083 // 1084 Status = EFI_BUFFER_TOO_SMALL; 1085 } 1086 1087 // 1088 // Close the connection if necessary 1089 // 1090 if (( EFI_ERROR ( Status )) 1091 && ( NULL == TcpPortHandle )) { 1092 // 1093 // TODO: Finish this code path 1094 // The new connection does not fit into the connection FIFO 1095 // 1096 // Process: 1097 // Call close 1098 // Release the resources 1099 1100 } 1101 1102 DBG_EXIT ( ); 1103 } 1104 1105 1106 /** 1107 Get the local socket address. 1108 1109 This routine returns the IPv6 address and TCP port number associated 1110 with the local socket. 1111 1112 This routine is called by ::EslSocketGetLocalAddress to determine the 1113 network address for the SOCK_STREAM or SOCK_SEQPACKET socket. 1114 1115 @param [in] pPort Address of an ::ESL_PORT structure. 1116 1117 @param [out] pSockAddr Network address to receive the local system address 1118 1119 **/ 1120 VOID 1121 EslTcp6LocalAddressGet ( 1122 IN ESL_PORT * pPort, 1123 OUT struct sockaddr * pSockAddr 1124 ) 1125 { 1126 struct sockaddr_in6 * pLocalAddress; 1127 ESL_TCP6_CONTEXT * pTcp6; 1128 1129 DBG_ENTER ( ); 1130 1131 // 1132 // Return the local address 1133 // 1134 pTcp6 = &pPort->Context.Tcp6; 1135 pLocalAddress = (struct sockaddr_in6 *)pSockAddr; 1136 pLocalAddress->sin6_family = AF_INET6; 1137 pLocalAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.StationPort ); 1138 CopyMem ( &pLocalAddress->sin6_addr, 1139 &pTcp6->ConfigData.AccessPoint.StationAddress.Addr[0], 1140 sizeof ( pLocalAddress->sin6_addr )); 1141 1142 DBG_EXIT ( ); 1143 } 1144 1145 1146 /** 1147 Set the local port address. 1148 1149 This routine sets the local port address. 1150 1151 This support routine is called by ::EslSocketPortAllocate. 1152 1153 @param [in] pPort Address of an ESL_PORT structure 1154 @param [in] pSockAddr Address of a sockaddr structure that contains the 1155 connection point on the local machine. An IPv6 address 1156 of INADDR_ANY specifies that the connection is made to 1157 all of the network stacks on the platform. Specifying a 1158 specific IPv6 address restricts the connection to the 1159 network stack supporting that address. Specifying zero 1160 for the port causes the network layer to assign a port 1161 number from the dynamic range. Specifying a specific 1162 port number causes the network layer to use that port. 1163 1164 @param [in] bBindTest TRUE = run bind testing 1165 1166 @retval EFI_SUCCESS The operation was successful 1167 1168 **/ 1169 EFI_STATUS 1170 EslTcp6LocalAddressSet ( 1171 IN ESL_PORT * pPort, 1172 IN CONST struct sockaddr * pSockAddr, 1173 IN BOOLEAN bBindTest 1174 ) 1175 { 1176 EFI_TCP6_ACCESS_POINT * pAccessPoint; 1177 CONST struct sockaddr_in6 * pIpAddress; 1178 EFI_STATUS Status; 1179 1180 DBG_ENTER ( ); 1181 1182 // 1183 // Validate the address 1184 // 1185 pIpAddress = (struct sockaddr_in6 *)pSockAddr; 1186 // 1187 // TODO: Fix the following check 1188 // 1189 /* 1190 if ( INADDR_BROADCAST == pIpAddress->sin6_addr.s_addr ) { 1191 // 1192 // The local address must not be the broadcast address 1193 // 1194 Status = EFI_INVALID_PARAMETER; 1195 pPort->pSocket->errno = EADDRNOTAVAIL; 1196 } 1197 else { 1198 */ 1199 { 1200 // 1201 // Set the local address 1202 // 1203 pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint; 1204 CopyMem ( &pAccessPoint->StationAddress.Addr[0], 1205 &pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ], 1206 sizeof ( pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ])); 1207 1208 // 1209 // Validate the IP address 1210 // 1211 pAccessPoint->StationPort = 0; 1212 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL ) 1213 : EFI_SUCCESS; 1214 if ( !EFI_ERROR ( Status )) { 1215 // 1216 // Set the port number 1217 // 1218 pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin6_port ); 1219 pPort->pSocket->bAddressSet = TRUE; 1220 1221 // 1222 // Display the local address 1223 // 1224 DEBUG (( DEBUG_BIND, 1225 "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", 1226 pPort, 1227 pAccessPoint->StationAddress.Addr[0], 1228 pAccessPoint->StationAddress.Addr[1], 1229 pAccessPoint->StationAddress.Addr[2], 1230 pAccessPoint->StationAddress.Addr[3], 1231 pAccessPoint->StationAddress.Addr[4], 1232 pAccessPoint->StationAddress.Addr[5], 1233 pAccessPoint->StationAddress.Addr[6], 1234 pAccessPoint->StationAddress.Addr[7], 1235 pAccessPoint->StationAddress.Addr[8], 1236 pAccessPoint->StationAddress.Addr[9], 1237 pAccessPoint->StationAddress.Addr[10], 1238 pAccessPoint->StationAddress.Addr[11], 1239 pAccessPoint->StationAddress.Addr[12], 1240 pAccessPoint->StationAddress.Addr[13], 1241 pAccessPoint->StationAddress.Addr[14], 1242 pAccessPoint->StationAddress.Addr[15], 1243 pAccessPoint->StationPort )); 1244 } 1245 } 1246 1247 // 1248 // Return the operation status 1249 // 1250 DBG_EXIT_STATUS ( Status ); 1251 return Status; 1252 } 1253 1254 1255 /** 1256 Free a receive packet 1257 1258 This routine performs the network specific operations necessary 1259 to free a receive packet. 1260 1261 This routine is called by ::EslSocketPortCloseTxDone to free a 1262 receive packet. 1263 1264 @param [in] pPacket Address of an ::ESL_PACKET structure. 1265 @param [in, out] pRxBytes Address of the count of RX bytes 1266 1267 **/ 1268 VOID 1269 EslTcp6PacketFree ( 1270 IN ESL_PACKET * pPacket, 1271 IN OUT size_t * pRxBytes 1272 ) 1273 { 1274 DBG_ENTER ( ); 1275 1276 // 1277 // Account for the receive bytes 1278 // 1279 *pRxBytes -= pPacket->Op.Tcp6Rx.RxData.DataLength; 1280 DBG_EXIT ( ); 1281 } 1282 1283 1284 /** 1285 Initialize the network specific portions of an ::ESL_PORT structure. 1286 1287 This routine initializes the network specific portions of an 1288 ::ESL_PORT structure for use by the socket. 1289 1290 This support routine is called by ::EslSocketPortAllocate 1291 to connect the socket with the underlying network adapter 1292 running the TCPv6 protocol. 1293 1294 @param [in] pPort Address of an ESL_PORT structure 1295 @param [in] DebugFlags Flags for debug messages 1296 1297 @retval EFI_SUCCESS - Socket successfully created 1298 1299 **/ 1300 EFI_STATUS 1301 EslTcp6PortAllocate ( 1302 IN ESL_PORT * pPort, 1303 IN UINTN DebugFlags 1304 ) 1305 { 1306 EFI_TCP6_ACCESS_POINT * pAccessPoint; 1307 ESL_SOCKET * pSocket; 1308 ESL_TCP6_CONTEXT * pTcp6; 1309 EFI_STATUS Status; 1310 1311 DBG_ENTER ( ); 1312 1313 // 1314 // Use for/break instead of goto 1315 for ( ; ; ) { 1316 // 1317 // Allocate the close event 1318 // 1319 pSocket = pPort->pSocket; 1320 pTcp6 = &pPort->Context.Tcp6; 1321 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, 1322 TPL_SOCKETS, 1323 (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete, 1324 pPort, 1325 &pTcp6->CloseToken.CompletionToken.Event); 1326 if ( EFI_ERROR ( Status )) { 1327 DEBUG (( DEBUG_ERROR | DebugFlags, 1328 "ERROR - Failed to create the close event, Status: %r\r\n", 1329 Status )); 1330 pSocket->errno = ENOMEM; 1331 break; 1332 } 1333 DEBUG (( DEBUG_CLOSE | DEBUG_POOL, 1334 "0x%08x: Created close event\r\n", 1335 pTcp6->CloseToken.CompletionToken.Event )); 1336 1337 // 1338 // Allocate the connection event 1339 // 1340 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, 1341 TPL_SOCKETS, 1342 (EFI_EVENT_NOTIFY)EslTcp6ConnectComplete, 1343 pPort, 1344 &pTcp6->ConnectToken.CompletionToken.Event); 1345 if ( EFI_ERROR ( Status )) { 1346 DEBUG (( DEBUG_ERROR | DebugFlags, 1347 "ERROR - Failed to create the connect event, Status: %r\r\n", 1348 Status )); 1349 pSocket->errno = ENOMEM; 1350 break; 1351 } 1352 DEBUG (( DEBUG_CLOSE | DEBUG_POOL, 1353 "0x%08x: Created connect event\r\n", 1354 pTcp6->ConnectToken.CompletionToken.Event )); 1355 1356 // 1357 // Initialize the port 1358 // 1359 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp6Tx.TxData ); 1360 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Tx.CompletionToken.Event ); 1361 pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP6_IO_TOKEN, Packet.TxData ); 1362 1363 // 1364 // Save the cancel, receive and transmit addresses 1365 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED 1366 // 1367 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv6->Configure; 1368 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv6->Poll; 1369 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Receive; 1370 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Transmit; 1371 1372 // 1373 // Set the configuration flags 1374 // 1375 pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint; 1376 pAccessPoint->ActiveFlag = FALSE; 1377 pTcp6->ConfigData.TrafficClass = 0; 1378 pTcp6->ConfigData.HopLimit = 255; 1379 break; 1380 } 1381 1382 // 1383 // Return the operation status 1384 // 1385 DBG_EXIT_STATUS ( Status ); 1386 return Status; 1387 } 1388 1389 1390 /** 1391 Close a Tcp6 port. 1392 1393 This routine releases the network specific resources allocated by 1394 ::EslTcp6PortAllocate. 1395 1396 This routine is called by ::EslSocketPortClose. 1397 See the \ref PortCloseStateMachine section. 1398 1399 @param [in] pPort Address of an ::ESL_PORT structure. 1400 1401 @retval EFI_SUCCESS The port is closed 1402 @retval other Port close error 1403 1404 **/ 1405 EFI_STATUS 1406 EslTcp6PortClose ( 1407 IN ESL_PORT * pPort 1408 ) 1409 { 1410 UINTN DebugFlags; 1411 ESL_TCP6_CONTEXT * pTcp6; 1412 EFI_STATUS Status; 1413 1414 DBG_ENTER ( ); 1415 1416 // 1417 // Locate the port in the socket list 1418 // 1419 Status = EFI_SUCCESS; 1420 DebugFlags = pPort->DebugFlags; 1421 pTcp6 = &pPort->Context.Tcp6; 1422 1423 // 1424 // Done with the connect event 1425 // 1426 if ( NULL != pTcp6->ConnectToken.CompletionToken.Event ) { 1427 Status = gBS->CloseEvent ( pTcp6->ConnectToken.CompletionToken.Event ); 1428 if ( !EFI_ERROR ( Status )) { 1429 DEBUG (( DebugFlags | DEBUG_POOL, 1430 "0x%08x: Closed connect event\r\n", 1431 pTcp6->ConnectToken.CompletionToken.Event )); 1432 } 1433 else { 1434 DEBUG (( DEBUG_ERROR | DebugFlags, 1435 "ERROR - Failed to close the connect event, Status: %r\r\n", 1436 Status )); 1437 ASSERT ( EFI_SUCCESS == Status ); 1438 } 1439 } 1440 1441 // 1442 // Done with the close event 1443 // 1444 if ( NULL != pTcp6->CloseToken.CompletionToken.Event ) { 1445 Status = gBS->CloseEvent ( pTcp6->CloseToken.CompletionToken.Event ); 1446 if ( !EFI_ERROR ( Status )) { 1447 DEBUG (( DebugFlags | DEBUG_POOL, 1448 "0x%08x: Closed close event\r\n", 1449 pTcp6->CloseToken.CompletionToken.Event )); 1450 } 1451 else { 1452 DEBUG (( DEBUG_ERROR | DebugFlags, 1453 "ERROR - Failed to close the close event, Status: %r\r\n", 1454 Status )); 1455 ASSERT ( EFI_SUCCESS == Status ); 1456 } 1457 } 1458 1459 // 1460 // Done with the listen completion event 1461 // 1462 if ( NULL != pTcp6->ListenToken.CompletionToken.Event ) { 1463 Status = gBS->CloseEvent ( pTcp6->ListenToken.CompletionToken.Event ); 1464 if ( !EFI_ERROR ( Status )) { 1465 DEBUG (( DebugFlags | DEBUG_POOL, 1466 "0x%08x: Closed listen completion event\r\n", 1467 pTcp6->ListenToken.CompletionToken.Event )); 1468 } 1469 else { 1470 DEBUG (( DEBUG_ERROR | DebugFlags, 1471 "ERROR - Failed to close the listen completion event, Status: %r\r\n", 1472 Status )); 1473 ASSERT ( EFI_SUCCESS == Status ); 1474 } 1475 } 1476 1477 // 1478 // Return the operation status 1479 // 1480 DBG_EXIT_STATUS ( Status ); 1481 return Status; 1482 } 1483 1484 1485 /** 1486 Perform the network specific close operation on the port. 1487 1488 This routine performs a cancel operations on the TCPv6 port to 1489 shutdown the receive operations on the port. 1490 1491 This routine is called by the ::EslSocketPortCloseTxDone 1492 routine after the port completes all of the transmission. 1493 1494 @param [in] pPort Address of an ::ESL_PORT structure. 1495 1496 @retval EFI_SUCCESS The port is closed, not normally returned 1497 @retval EFI_NOT_READY The port is still closing 1498 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state, 1499 most likely the routine was called already. 1500 1501 **/ 1502 EFI_STATUS 1503 EslTcp6PortCloseOp ( 1504 IN ESL_PORT * pPort 1505 ) 1506 { 1507 ESL_TCP6_CONTEXT * pTcp6; 1508 EFI_TCP6_PROTOCOL * pTcp6Protocol; 1509 EFI_STATUS Status; 1510 1511 DBG_ENTER ( ); 1512 1513 // 1514 // Close the configured port 1515 // 1516 Status = EFI_SUCCESS; 1517 pTcp6 = &pPort->Context.Tcp6; 1518 pTcp6Protocol = pPort->pProtocol.TCPv6; 1519 pTcp6->CloseToken.AbortOnClose = pPort->bCloseNow; 1520 Status = pTcp6Protocol->Close ( pTcp6Protocol, 1521 &pTcp6->CloseToken ); 1522 if ( !EFI_ERROR ( Status )) { 1523 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO, 1524 "0x%08x: Port close started\r\n", 1525 pPort )); 1526 } 1527 else { 1528 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO, 1529 "ERROR - Close failed on port 0x%08x, Status: %r\r\n", 1530 pPort, 1531 Status )); 1532 } 1533 1534 // 1535 // Return the operation status 1536 // 1537 DBG_EXIT_STATUS ( Status ); 1538 return Status; 1539 } 1540 1541 1542 /** 1543 Receive data from a network connection. 1544 1545 This routine attempts to return buffered data to the caller. The 1546 data is removed from the urgent queue if the message flag MSG_OOB 1547 is specified, otherwise data is removed from the normal queue. 1548 See the \ref ReceiveEngine section. 1549 1550 This routine is called by ::EslSocketReceive to handle the network 1551 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET 1552 sockets. 1553 1554 @param [in] pPort Address of an ::ESL_PORT structure. 1555 1556 @param [in] pPacket Address of an ::ESL_PACKET structure. 1557 1558 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed 1559 1560 @param [in] BufferLength Length of the the buffer 1561 1562 @param [in] pBuffer Address of a buffer to receive the data. 1563 1564 @param [in] pDataLength Number of received data bytes in the buffer. 1565 1566 @param [out] pAddress Network address to receive the remote system address 1567 1568 @param [out] pSkipBytes Address to receive the number of bytes skipped 1569 1570 @return Returns the address of the next free byte in the buffer. 1571 1572 **/ 1573 UINT8 * 1574 EslTcp6Receive ( 1575 IN ESL_PORT * pPort, 1576 IN ESL_PACKET * pPacket, 1577 IN BOOLEAN * pbConsumePacket, 1578 IN size_t BufferLength, 1579 IN UINT8 * pBuffer, 1580 OUT size_t * pDataLength, 1581 OUT struct sockaddr * pAddress, 1582 OUT size_t * pSkipBytes 1583 ) 1584 { 1585 size_t DataLength; 1586 struct sockaddr_in6 * pRemoteAddress; 1587 ESL_TCP6_CONTEXT * pTcp6; 1588 1589 DBG_ENTER ( ); 1590 1591 // 1592 // Return the remote system address if requested 1593 // 1594 if ( NULL != pAddress ) { 1595 // 1596 // Build the remote address 1597 // 1598 pTcp6 = &pPort->Context.Tcp6; 1599 DEBUG (( DEBUG_RX, 1600 "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n", 1601 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0], 1602 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1], 1603 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2], 1604 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3], 1605 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4], 1606 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5], 1607 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6], 1608 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7], 1609 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8], 1610 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9], 1611 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10], 1612 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11], 1613 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12], 1614 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13], 1615 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14], 1616 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15], 1617 pTcp6->ConfigData.AccessPoint.RemotePort )); 1618 pRemoteAddress = (struct sockaddr_in6 *)pAddress; 1619 CopyMem ( &pRemoteAddress->sin6_addr, 1620 &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0], 1621 sizeof ( pRemoteAddress->sin6_addr )); 1622 pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort ); 1623 } 1624 1625 // 1626 // Determine the amount of received data 1627 // 1628 DataLength = pPacket->ValidBytes; 1629 if ( BufferLength < DataLength ) { 1630 DataLength = BufferLength; 1631 } 1632 1633 // 1634 // Move the data into the buffer 1635 // 1636 DEBUG (( DEBUG_RX, 1637 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n", 1638 pPort, 1639 pPacket, 1640 pBuffer, 1641 DataLength )); 1642 CopyMem ( pBuffer, pPacket->pBuffer, DataLength ); 1643 1644 // 1645 // Set the next buffer address 1646 // 1647 pBuffer += DataLength; 1648 1649 // 1650 // Determine if the data is being read 1651 // 1652 if ( *pbConsumePacket ) { 1653 // 1654 // Account for the bytes consumed 1655 // 1656 pPacket->pBuffer += DataLength; 1657 pPacket->ValidBytes -= DataLength; 1658 DEBUG (( DEBUG_RX, 1659 "0x%08x: Port account for 0x%08x bytes\r\n", 1660 pPort, 1661 DataLength )); 1662 1663 // 1664 // Determine if the entire packet was consumed 1665 // 1666 if (( 0 == pPacket->ValidBytes ) 1667 || ( SOCK_STREAM != pPort->pSocket->Type )) { 1668 // 1669 // All done with this packet 1670 // Account for any discarded data 1671 // 1672 *pSkipBytes = pPacket->ValidBytes; 1673 } 1674 else 1675 { 1676 // 1677 // More data to consume later 1678 // 1679 *pbConsumePacket = FALSE; 1680 } 1681 } 1682 1683 // 1684 // Return the data length and the buffer address 1685 // 1686 *pDataLength = DataLength; 1687 DBG_EXIT_HEX ( pBuffer ); 1688 return pBuffer; 1689 } 1690 1691 1692 /** 1693 Get the remote socket address. 1694 1695 This routine returns the address of the remote connection point 1696 associated with the SOCK_STREAM or SOCK_SEQPACKET socket. 1697 1698 This routine is called by ::EslSocketGetPeerAddress to detemine 1699 the TCPv6 address and por number associated with the network adapter. 1700 1701 @param [in] pPort Address of an ::ESL_PORT structure. 1702 1703 @param [out] pAddress Network address to receive the remote system address 1704 1705 **/ 1706 VOID 1707 EslTcp6RemoteAddressGet ( 1708 IN ESL_PORT * pPort, 1709 OUT struct sockaddr * pAddress 1710 ) 1711 { 1712 struct sockaddr_in6 * pRemoteAddress; 1713 ESL_TCP6_CONTEXT * pTcp6; 1714 1715 DBG_ENTER ( ); 1716 1717 // 1718 // Return the remote address 1719 // 1720 pTcp6 = &pPort->Context.Tcp6; 1721 pRemoteAddress = (struct sockaddr_in6 *)pAddress; 1722 pRemoteAddress->sin6_family = AF_INET6; 1723 pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort ); 1724 CopyMem ( &pRemoteAddress->sin6_addr, 1725 &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0], 1726 sizeof ( pRemoteAddress->sin6_addr )); 1727 1728 DBG_EXIT ( ); 1729 } 1730 1731 1732 /** 1733 Set the remote address 1734 1735 This routine sets the remote address in the port. 1736 1737 This routine is called by ::EslSocketConnect to specify the 1738 remote network address. 1739 1740 @param [in] pPort Address of an ::ESL_PORT structure. 1741 1742 @param [in] pSockAddr Network address of the remote system. 1743 1744 @param [in] SockAddrLength Length in bytes of the network address. 1745 1746 @retval EFI_SUCCESS The operation was successful 1747 1748 **/ 1749 EFI_STATUS 1750 EslTcp6RemoteAddressSet ( 1751 IN ESL_PORT * pPort, 1752 IN CONST struct sockaddr * pSockAddr, 1753 IN socklen_t SockAddrLength 1754 ) 1755 { 1756 CONST struct sockaddr_in6 * pRemoteAddress; 1757 ESL_TCP6_CONTEXT * pTcp6; 1758 EFI_STATUS Status; 1759 1760 DBG_ENTER ( ); 1761 1762 // 1763 // Set the remote address 1764 // 1765 pTcp6 = &pPort->Context.Tcp6; 1766 pRemoteAddress = (struct sockaddr_in6 *)pSockAddr; 1767 CopyMem ( &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr [ 0 ], 1768 &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ], 1769 sizeof ( pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 )); 1770 pTcp6->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port ); 1771 Status = EFI_SUCCESS; 1772 1773 // 1774 // TODO: Fix the following check 1775 // 1776 /* 1777 if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) { 1778 DEBUG (( DEBUG_CONNECT, 1779 "ERROR - Invalid remote address\r\n" )); 1780 Status = EFI_INVALID_PARAMETER; 1781 pPort->pSocket->errno = EAFNOSUPPORT; 1782 } 1783 */ 1784 1785 // 1786 // Return the operation status 1787 // 1788 DBG_EXIT_STATUS ( Status ); 1789 return Status; 1790 } 1791 1792 1793 /** 1794 Process the receive completion 1795 1796 This routine queues the data in FIFO order in either the urgent 1797 or normal data queues depending upon the type of data received. 1798 See the \ref ReceiveEngine section. 1799 1800 This routine is called by the TCPv6 driver when some data is 1801 received. 1802 1803 Buffer the data that was just received. 1804 1805 @param [in] Event The receive completion event 1806 1807 @param [in] pIo Address of an ::ESL_IO_MGMT structure 1808 1809 **/ 1810 VOID 1811 EslTcp6RxComplete ( 1812 IN EFI_EVENT Event, 1813 IN ESL_IO_MGMT * pIo 1814 ) 1815 { 1816 BOOLEAN bUrgent; 1817 size_t LengthInBytes; 1818 ESL_PACKET * pPacket; 1819 EFI_STATUS Status; 1820 1821 DBG_ENTER ( ); 1822 1823 // 1824 // Get the operation status. 1825 // 1826 Status = pIo->Token.Tcp6Rx.CompletionToken.Status; 1827 1828 // 1829 // +--------------------+ +---------------------------+ 1830 // | ESL_IO_MGMT | | ESL_PACKET | 1831 // | | | | 1832 // | +---------------+ +-----------------------+ | 1833 // | | Token | | EFI_Tcp6_RECEIVE_DATA | | 1834 // | | RxData --> | | | 1835 // | | | +-----------------------+---+ 1836 // | | Event | | Data Buffer | 1837 // +----+---------------+ | | 1838 // | | 1839 // +---------------------------+ 1840 // 1841 // 1842 // Duplicate the buffer address and length for use by the 1843 // buffer handling code in EslTcp6Receive. These fields are 1844 // used when a partial read is done of the data from the 1845 // packet. 1846 // 1847 pPacket = pIo->pPacket; 1848 pPacket->pBuffer = pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer; 1849 LengthInBytes = pPacket->Op.Tcp6Rx.RxData.DataLength; 1850 pPacket->ValidBytes = LengthInBytes; 1851 1852 // 1853 // Get the data type so that it may be linked to the 1854 // correct receive buffer list on the ESL_SOCKET structure 1855 // 1856 bUrgent = pPacket->Op.Tcp6Rx.RxData.UrgentFlag; 1857 1858 // 1859 // Complete this request 1860 // 1861 EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent ); 1862 DBG_EXIT ( ); 1863 } 1864 1865 1866 /** 1867 Start a receive operation 1868 1869 This routine posts a receive buffer to the TCPv6 driver. 1870 See the \ref ReceiveEngine section. 1871 1872 This support routine is called by EslSocketRxStart. 1873 1874 @param [in] pPort Address of an ::ESL_PORT structure. 1875 @param [in] pIo Address of an ::ESL_IO_MGMT structure. 1876 1877 **/ 1878 VOID 1879 EslTcp6RxStart ( 1880 IN ESL_PORT * pPort, 1881 IN ESL_IO_MGMT * pIo 1882 ) 1883 { 1884 ESL_PACKET * pPacket; 1885 1886 DBG_ENTER ( ); 1887 1888 // 1889 // Initialize the buffer for receive 1890 // 1891 pPacket = pIo->pPacket; 1892 pIo->Token.Tcp6Rx.Packet.RxData = &pPacket->Op.Tcp6Rx.RxData; 1893 pPacket->Op.Tcp6Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp6Rx.Buffer ); 1894 pPacket->Op.Tcp6Rx.RxData.FragmentCount = 1; 1895 pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp6Rx.RxData.DataLength; 1896 pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Rx.Buffer[0]; 1897 1898 DBG_EXIT ( ); 1899 } 1900 1901 1902 /** 1903 Determine if the socket is configured. 1904 1905 This routine uses the flag ESL_SOCKET::bConfigured to determine 1906 if the network layer's configuration routine has been called. 1907 1908 This routine is called by EslSocketIsConfigured to verify 1909 that the socket has been configured. 1910 1911 @param [in] pSocket Address of an ::ESL_SOCKET structure. 1912 1913 @retval EFI_SUCCESS - The port is connected 1914 @retval EFI_NOT_STARTED - The port is not connected 1915 1916 **/ 1917 EFI_STATUS 1918 EslTcp6SocketIsConfigured ( 1919 IN ESL_SOCKET * pSocket 1920 ) 1921 { 1922 EFI_STATUS Status; 1923 1924 DBG_ENTER ( ); 1925 1926 // 1927 // Determine the socket configuration status 1928 // 1929 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED; 1930 1931 // 1932 // Return the port connected state. 1933 // 1934 DBG_EXIT_STATUS ( Status ); 1935 return Status; 1936 } 1937 1938 1939 /** 1940 Buffer data for transmission over a network connection. 1941 1942 This routine buffers data for the transmit engine in one of two 1943 queues, one for urgent (out-of-band) data and the other for normal 1944 data. The urgent data is provided to TCP as soon as it is available, 1945 allowing the TCP layer to schedule transmission of the urgent data 1946 between packets of normal data. 1947 1948 This routine is called by ::EslSocketTransmit to buffer 1949 data for transmission. When the \ref TransmitEngine has resources, 1950 this routine will start the transmission of the next buffer on 1951 the network connection. 1952 1953 Transmission errors are returned during the next transmission or 1954 during the close operation. Only buffering errors are returned 1955 during the current transmission attempt. 1956 1957 @param [in] pSocket Address of an ::ESL_SOCKET structure 1958 1959 @param [in] Flags Message control flags 1960 1961 @param [in] BufferLength Length of the the buffer 1962 1963 @param [in] pBuffer Address of a buffer to receive the data. 1964 1965 @param [in] pDataLength Number of received data bytes in the buffer. 1966 1967 @param [in] pAddress Network address of the remote system address 1968 1969 @param [in] AddressLength Length of the remote network address structure 1970 1971 @retval EFI_SUCCESS - Socket data successfully buffered 1972 1973 **/ 1974 EFI_STATUS 1975 EslTcp6TxBuffer ( 1976 IN ESL_SOCKET * pSocket, 1977 IN int Flags, 1978 IN size_t BufferLength, 1979 IN CONST UINT8 * pBuffer, 1980 OUT size_t * pDataLength, 1981 IN const struct sockaddr * pAddress, 1982 IN socklen_t AddressLength 1983 ) 1984 { 1985 BOOLEAN bUrgent; 1986 BOOLEAN bUrgentQueue; 1987 ESL_PACKET * pPacket; 1988 ESL_IO_MGMT ** ppActive; 1989 ESL_IO_MGMT ** ppFree; 1990 ESL_PORT * pPort; 1991 ESL_PACKET ** ppQueueHead; 1992 ESL_PACKET ** ppQueueTail; 1993 ESL_PACKET * pPreviousPacket; 1994 size_t * pTxBytes; 1995 EFI_TCP6_TRANSMIT_DATA * pTxData; 1996 EFI_STATUS Status; 1997 EFI_TPL TplPrevious; 1998 1999 DBG_ENTER ( ); 2000 2001 // 2002 // Assume failure 2003 // 2004 Status = EFI_UNSUPPORTED; 2005 pSocket->errno = ENOTCONN; 2006 *pDataLength = 0; 2007 2008 // 2009 // Verify that the socket is connected 2010 // 2011 if ( SOCKET_STATE_CONNECTED == pSocket->State ) { 2012 // 2013 // Locate the port 2014 // 2015 pPort = pSocket->pPortList; 2016 if ( NULL != pPort ) { 2017 // 2018 // Determine the queue head 2019 // 2020 bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB )); 2021 bUrgentQueue = bUrgent 2022 && ( !pSocket->bOobInLine ) 2023 && pSocket->pApi->bOobSupported; 2024 if ( bUrgentQueue ) { 2025 ppQueueHead = &pSocket->pTxOobPacketListHead; 2026 ppQueueTail = &pSocket->pTxOobPacketListTail; 2027 ppActive = &pPort->pTxOobActive; 2028 ppFree = &pPort->pTxOobFree; 2029 pTxBytes = &pSocket->TxOobBytes; 2030 } 2031 else { 2032 ppQueueHead = &pSocket->pTxPacketListHead; 2033 ppQueueTail = &pSocket->pTxPacketListTail; 2034 ppActive = &pPort->pTxActive; 2035 ppFree = &pPort->pTxFree; 2036 pTxBytes = &pSocket->TxBytes; 2037 } 2038 2039 // 2040 // Verify that there is enough room to buffer another 2041 // transmit operation 2042 // 2043 if ( pSocket->MaxTxBuf > *pTxBytes ) { 2044 if ( pPort->bTxFlowControl ) { 2045 DEBUG (( DEBUG_TX, 2046 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n", 2047 pPort, 2048 pSocket->MaxTxBuf, 2049 *pTxBytes )); 2050 pPort->bTxFlowControl = FALSE; 2051 } 2052 2053 // 2054 // Attempt to allocate the packet 2055 // 2056 Status = EslSocketPacketAllocate ( &pPacket, 2057 sizeof ( pPacket->Op.Tcp6Tx ) 2058 - sizeof ( pPacket->Op.Tcp6Tx.Buffer ) 2059 + BufferLength, 2060 0, 2061 DEBUG_TX ); 2062 if ( !EFI_ERROR ( Status )) { 2063 // 2064 // Initialize the transmit operation 2065 // 2066 pTxData = &pPacket->Op.Tcp6Tx.TxData; 2067 pTxData->Push = TRUE || bUrgent; 2068 pTxData->Urgent = bUrgent; 2069 pTxData->DataLength = (UINT32) BufferLength; 2070 pTxData->FragmentCount = 1; 2071 pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength; 2072 pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Tx.Buffer[0]; 2073 2074 // 2075 // Copy the data into the buffer 2076 // 2077 CopyMem ( &pPacket->Op.Tcp6Tx.Buffer[0], 2078 pBuffer, 2079 BufferLength ); 2080 2081 // 2082 // Synchronize with the socket layer 2083 // 2084 RAISE_TPL ( TplPrevious, TPL_SOCKETS ); 2085 2086 // 2087 // Stop transmission after an error 2088 // 2089 if ( !EFI_ERROR ( pSocket->TxError )) { 2090 // 2091 // Display the request 2092 // 2093 DEBUG (( DEBUG_TX, 2094 "Send %d %s bytes from 0x%08x\r\n", 2095 BufferLength, 2096 bUrgent ? L"urgent" : L"normal", 2097 pBuffer )); 2098 2099 // 2100 // Queue the data for transmission 2101 // 2102 pPacket->pNext = NULL; 2103 pPreviousPacket = *ppQueueTail; 2104 if ( NULL == pPreviousPacket ) { 2105 *ppQueueHead = pPacket; 2106 } 2107 else { 2108 pPreviousPacket->pNext = pPacket; 2109 } 2110 *ppQueueTail = pPacket; 2111 DEBUG (( DEBUG_TX, 2112 "0x%08x: Packet on %s transmit list\r\n", 2113 pPacket, 2114 bUrgentQueue ? L"urgent" : L"normal" )); 2115 2116 // 2117 // Account for the buffered data 2118 // 2119 *pTxBytes += BufferLength; 2120 *pDataLength = BufferLength; 2121 2122 // 2123 // Start the transmit engine if it is idle 2124 // 2125 if ( NULL != *ppFree ) { 2126 EslSocketTxStart ( pPort, 2127 ppQueueHead, 2128 ppQueueTail, 2129 ppActive, 2130 ppFree ); 2131 } 2132 } 2133 else { 2134 // 2135 // Previous transmit error 2136 // Stop transmission 2137 // 2138 Status = pSocket->TxError; 2139 pSocket->errno = EIO; 2140 2141 // 2142 // Free the packet 2143 // 2144 EslSocketPacketFree ( pPacket, DEBUG_TX ); 2145 } 2146 2147 // 2148 // Release the socket layer synchronization 2149 // 2150 RESTORE_TPL ( TplPrevious ); 2151 } 2152 else { 2153 // 2154 // Packet allocation failed 2155 // 2156 pSocket->errno = ENOMEM; 2157 } 2158 } 2159 else { 2160 if ( !pPort->bTxFlowControl ) { 2161 DEBUG (( DEBUG_TX, 2162 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n", 2163 pPort, 2164 pSocket->MaxTxBuf, 2165 *pTxBytes )); 2166 pPort->bTxFlowControl = TRUE; 2167 } 2168 // 2169 // Not enough buffer space available 2170 // 2171 pSocket->errno = EAGAIN; 2172 Status = EFI_NOT_READY; 2173 } 2174 } 2175 } 2176 2177 // 2178 // Return the operation status 2179 // 2180 DBG_EXIT_STATUS ( Status ); 2181 return Status; 2182 } 2183 2184 2185 /** 2186 Process the normal data transmit completion 2187 2188 This routine use ::EslSocketTxComplete to perform the transmit 2189 completion processing for normal data. 2190 2191 This routine is called by the TCPv6 network layer when a 2192 normal data transmit request completes. 2193 2194 @param [in] Event The normal transmit completion event 2195 2196 @param [in] pIo The ESL_IO_MGMT structure address 2197 2198 **/ 2199 VOID 2200 EslTcp6TxComplete ( 2201 IN EFI_EVENT Event, 2202 IN ESL_IO_MGMT * pIo 2203 ) 2204 { 2205 UINT32 LengthInBytes; 2206 ESL_PACKET * pPacket; 2207 ESL_PORT * pPort; 2208 ESL_SOCKET * pSocket; 2209 EFI_STATUS Status; 2210 2211 DBG_ENTER ( ); 2212 2213 // 2214 // Locate the active transmit packet 2215 // 2216 pPacket = pIo->pPacket; 2217 pPort = pIo->pPort; 2218 pSocket = pPort->pSocket; 2219 2220 // 2221 // Get the transmit length and status 2222 // 2223 LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength; 2224 pSocket->TxBytes -= LengthInBytes; 2225 Status = pIo->Token.Tcp6Tx.CompletionToken.Status; 2226 2227 // 2228 // Complete the transmit operation 2229 // 2230 EslSocketTxComplete ( pIo, 2231 LengthInBytes, 2232 Status, 2233 "Normal ", 2234 &pSocket->pTxPacketListHead, 2235 &pSocket->pTxPacketListTail, 2236 &pPort->pTxActive, 2237 &pPort->pTxFree ); 2238 DBG_EXIT ( ); 2239 } 2240 2241 2242 /** 2243 Process the urgent data transmit completion 2244 2245 This routine use ::EslSocketTxComplete to perform the transmit 2246 completion processing for urgent data. 2247 2248 This routine is called by the TCPv6 network layer when a 2249 urgent data transmit request completes. 2250 2251 @param [in] Event The urgent transmit completion event 2252 2253 @param [in] pIo The ESL_IO_MGMT structure address 2254 2255 **/ 2256 VOID 2257 EslTcp6TxOobComplete ( 2258 IN EFI_EVENT Event, 2259 IN ESL_IO_MGMT * pIo 2260 ) 2261 { 2262 UINT32 LengthInBytes; 2263 ESL_PACKET * pPacket; 2264 ESL_PORT * pPort; 2265 ESL_SOCKET * pSocket; 2266 EFI_STATUS Status; 2267 2268 DBG_ENTER ( ); 2269 2270 // 2271 // Locate the active transmit packet 2272 // 2273 pPacket = pIo->pPacket; 2274 pPort = pIo->pPort; 2275 pSocket = pPort->pSocket; 2276 2277 // 2278 // Get the transmit length and status 2279 // 2280 LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength; 2281 pSocket->TxOobBytes -= LengthInBytes; 2282 Status = pIo->Token.Tcp6Tx.CompletionToken.Status; 2283 2284 // 2285 // Complete the transmit operation 2286 // 2287 EslSocketTxComplete ( pIo, 2288 LengthInBytes, 2289 Status, 2290 "Urgent ", 2291 &pSocket->pTxOobPacketListHead, 2292 &pSocket->pTxOobPacketListTail, 2293 &pPort->pTxOobActive, 2294 &pPort->pTxOobFree ); 2295 DBG_EXIT ( ); 2296 } 2297 2298 2299 /** 2300 Verify the adapter's IP address 2301 2302 This support routine is called by EslSocketBindTest. 2303 2304 @param [in] pPort Address of an ::ESL_PORT structure. 2305 @param [in] pConfigData Address of the configuration data 2306 2307 @retval EFI_SUCCESS - The IP address is valid 2308 @retval EFI_NOT_STARTED - The IP address is invalid 2309 2310 **/ 2311 EFI_STATUS 2312 EslTcp6VerifyLocalIpAddress ( 2313 IN ESL_PORT * pPort, 2314 IN EFI_TCP6_CONFIG_DATA * pConfigData 2315 ) 2316 { 2317 UINTN AddressCount; 2318 EFI_IP6_ADDRESS_INFO * pAddressInfo; 2319 UINTN DataSize; 2320 EFI_TCP6_ACCESS_POINT * pAccess; 2321 EFI_IP6_CONFIG_INTERFACE_INFO * pIpConfigData; 2322 EFI_IP6_CONFIG_PROTOCOL * pIpConfigProtocol; 2323 ESL_SERVICE * pService; 2324 EFI_STATUS Status; 2325 2326 DBG_ENTER ( ); 2327 2328 // 2329 // Use break instead of goto 2330 // 2331 pIpConfigData = NULL; 2332 for ( ; ; ) { 2333 // 2334 // Determine if the IP address is specified 2335 // 2336 pAccess = &pConfigData->AccessPoint; 2337 DEBUG (( DEBUG_BIND, 2338 "Requested IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n", 2339 pAccess->StationAddress.Addr[0], 2340 pAccess->StationAddress.Addr[1], 2341 pAccess->StationAddress.Addr[2], 2342 pAccess->StationAddress.Addr[3], 2343 pAccess->StationAddress.Addr[4], 2344 pAccess->StationAddress.Addr[5], 2345 pAccess->StationAddress.Addr[6], 2346 pAccess->StationAddress.Addr[7], 2347 pAccess->StationAddress.Addr[8], 2348 pAccess->StationAddress.Addr[9], 2349 pAccess->StationAddress.Addr[10], 2350 pAccess->StationAddress.Addr[11], 2351 pAccess->StationAddress.Addr[12], 2352 pAccess->StationAddress.Addr[13], 2353 pAccess->StationAddress.Addr[14], 2354 pAccess->StationAddress.Addr[15])); 2355 if (( 0 == pAccess->StationAddress.Addr [ 0 ]) 2356 && ( 0 == pAccess->StationAddress.Addr [ 1 ]) 2357 && ( 0 == pAccess->StationAddress.Addr [ 2 ]) 2358 && ( 0 == pAccess->StationAddress.Addr [ 3 ]) 2359 && ( 0 == pAccess->StationAddress.Addr [ 4 ]) 2360 && ( 0 == pAccess->StationAddress.Addr [ 5 ]) 2361 && ( 0 == pAccess->StationAddress.Addr [ 6 ]) 2362 && ( 0 == pAccess->StationAddress.Addr [ 7 ]) 2363 && ( 0 == pAccess->StationAddress.Addr [ 8 ]) 2364 && ( 0 == pAccess->StationAddress.Addr [ 9 ]) 2365 && ( 0 == pAccess->StationAddress.Addr [ 10 ]) 2366 && ( 0 == pAccess->StationAddress.Addr [ 11 ]) 2367 && ( 0 == pAccess->StationAddress.Addr [ 12 ]) 2368 && ( 0 == pAccess->StationAddress.Addr [ 13 ]) 2369 && ( 0 == pAccess->StationAddress.Addr [ 14 ]) 2370 && ( 0 == pAccess->StationAddress.Addr [ 15 ])) 2371 { 2372 Status = EFI_SUCCESS; 2373 break; 2374 } 2375 2376 // 2377 // Open the configuration protocol 2378 // 2379 pService = pPort->pService; 2380 Status = gBS->OpenProtocol ( pService->Controller, 2381 &gEfiIp6ConfigProtocolGuid, 2382 (VOID **)&pIpConfigProtocol, 2383 NULL, 2384 NULL, 2385 EFI_OPEN_PROTOCOL_GET_PROTOCOL ); 2386 if ( EFI_ERROR ( Status )) { 2387 DEBUG (( DEBUG_ERROR, 2388 "ERROR - IP Configuration Protocol not available, Status: %r\r\n", 2389 Status )); 2390 break; 2391 } 2392 2393 // 2394 // Get the IP configuration data size 2395 // 2396 DataSize = 0; 2397 Status = pIpConfigProtocol->GetData ( pIpConfigProtocol, 2398 Ip6ConfigDataTypeInterfaceInfo, 2399 &DataSize, 2400 NULL ); 2401 if ( EFI_BUFFER_TOO_SMALL != Status ) { 2402 DEBUG (( DEBUG_ERROR, 2403 "ERROR - Failed to get IP Configuration data size, Status: %r\r\n", 2404 Status )); 2405 break; 2406 } 2407 2408 // 2409 // Allocate the configuration data buffer 2410 // 2411 pIpConfigData = AllocatePool ( DataSize ); 2412 if ( NULL == pIpConfigData ) { 2413 DEBUG (( DEBUG_ERROR, 2414 "ERROR - Not enough memory to allocate IP Configuration data!\r\n" )); 2415 Status = EFI_OUT_OF_RESOURCES; 2416 break; 2417 } 2418 2419 // 2420 // Get the IP configuration 2421 // 2422 Status = pIpConfigProtocol->GetData ( pIpConfigProtocol, 2423 Ip6ConfigDataTypeInterfaceInfo, 2424 &DataSize, 2425 pIpConfigData ); 2426 if ( EFI_ERROR ( Status )) { 2427 DEBUG (( DEBUG_ERROR, 2428 "ERROR - Failed to return IP Configuration data, Status: %r\r\n", 2429 Status )); 2430 break; 2431 } 2432 2433 // 2434 // Display the current configuration 2435 // 2436 DEBUG (( DEBUG_BIND, 2437 "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n", 2438 pIpConfigData->HwAddress.Addr [ 0 ], 2439 pIpConfigData->HwAddress.Addr [ 1 ], 2440 pIpConfigData->HwAddress.Addr [ 2 ], 2441 pIpConfigData->HwAddress.Addr [ 3 ], 2442 pIpConfigData->HwAddress.Addr [ 4 ], 2443 pIpConfigData->HwAddress.Addr [ 5 ], 2444 pIpConfigData->HwAddress.Addr [ 6 ], 2445 pIpConfigData->HwAddress.Addr [ 7 ], 2446 pIpConfigData->HwAddress.Addr [ 8 ], 2447 pIpConfigData->HwAddress.Addr [ 9 ], 2448 pIpConfigData->HwAddress.Addr [ 10 ], 2449 pIpConfigData->HwAddress.Addr [ 11 ], 2450 pIpConfigData->HwAddress.Addr [ 12 ], 2451 pIpConfigData->HwAddress.Addr [ 13 ], 2452 pIpConfigData->HwAddress.Addr [ 14 ], 2453 pIpConfigData->HwAddress.Addr [ 15 ])); 2454 2455 // 2456 // Validate the hardware address 2457 // 2458 Status = EFI_SUCCESS; 2459 if (( 16 == pIpConfigData->HwAddressSize ) 2460 && ( pAccess->StationAddress.Addr [ 0 ] == pIpConfigData->HwAddress.Addr [ 0 ]) 2461 && ( pAccess->StationAddress.Addr [ 1 ] == pIpConfigData->HwAddress.Addr [ 1 ]) 2462 && ( pAccess->StationAddress.Addr [ 2 ] == pIpConfigData->HwAddress.Addr [ 2 ]) 2463 && ( pAccess->StationAddress.Addr [ 3 ] == pIpConfigData->HwAddress.Addr [ 3 ]) 2464 && ( pAccess->StationAddress.Addr [ 4 ] == pIpConfigData->HwAddress.Addr [ 4 ]) 2465 && ( pAccess->StationAddress.Addr [ 5 ] == pIpConfigData->HwAddress.Addr [ 5 ]) 2466 && ( pAccess->StationAddress.Addr [ 6 ] == pIpConfigData->HwAddress.Addr [ 6 ]) 2467 && ( pAccess->StationAddress.Addr [ 7 ] == pIpConfigData->HwAddress.Addr [ 7 ]) 2468 && ( pAccess->StationAddress.Addr [ 8 ] == pIpConfigData->HwAddress.Addr [ 8 ]) 2469 && ( pAccess->StationAddress.Addr [ 9 ] == pIpConfigData->HwAddress.Addr [ 9 ]) 2470 && ( pAccess->StationAddress.Addr [ 10 ] == pIpConfigData->HwAddress.Addr [ 10 ]) 2471 && ( pAccess->StationAddress.Addr [ 11 ] == pIpConfigData->HwAddress.Addr [ 11 ]) 2472 && ( pAccess->StationAddress.Addr [ 12 ] == pIpConfigData->HwAddress.Addr [ 12 ]) 2473 && ( pAccess->StationAddress.Addr [ 13 ] == pIpConfigData->HwAddress.Addr [ 13 ]) 2474 && ( pAccess->StationAddress.Addr [ 14 ] == pIpConfigData->HwAddress.Addr [ 14 ]) 2475 && ( pAccess->StationAddress.Addr [ 15 ] == pIpConfigData->HwAddress.Addr [ 15 ])) { 2476 break; 2477 } 2478 2479 // 2480 // Walk the list of other IP addresses assigned to this adapter 2481 // 2482 for ( AddressCount = 0; pIpConfigData->AddressInfoCount > AddressCount; AddressCount += 1 ) { 2483 pAddressInfo = &pIpConfigData->AddressInfo [ AddressCount ]; 2484 2485 // 2486 // Display the IP address 2487 // 2488 DEBUG (( DEBUG_BIND, 2489 "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n", 2490 pAddressInfo->Address.Addr [ 0 ], 2491 pAddressInfo->Address.Addr [ 1 ], 2492 pAddressInfo->Address.Addr [ 2 ], 2493 pAddressInfo->Address.Addr [ 3 ], 2494 pAddressInfo->Address.Addr [ 4 ], 2495 pAddressInfo->Address.Addr [ 5 ], 2496 pAddressInfo->Address.Addr [ 6 ], 2497 pAddressInfo->Address.Addr [ 7 ], 2498 pAddressInfo->Address.Addr [ 8 ], 2499 pAddressInfo->Address.Addr [ 9 ], 2500 pAddressInfo->Address.Addr [ 10 ], 2501 pAddressInfo->Address.Addr [ 11 ], 2502 pAddressInfo->Address.Addr [ 12 ], 2503 pAddressInfo->Address.Addr [ 13 ], 2504 pAddressInfo->Address.Addr [ 14 ], 2505 pAddressInfo->Address.Addr [ 15 ])); 2506 2507 // 2508 // Validate the IP address 2509 // 2510 if (( pAccess->StationAddress.Addr [ 0 ] == pAddressInfo->Address.Addr [ 0 ]) 2511 && ( pAccess->StationAddress.Addr [ 1 ] == pAddressInfo->Address.Addr [ 1 ]) 2512 && ( pAccess->StationAddress.Addr [ 2 ] == pAddressInfo->Address.Addr [ 2 ]) 2513 && ( pAccess->StationAddress.Addr [ 3 ] == pAddressInfo->Address.Addr [ 3 ]) 2514 && ( pAccess->StationAddress.Addr [ 4 ] == pAddressInfo->Address.Addr [ 4 ]) 2515 && ( pAccess->StationAddress.Addr [ 5 ] == pAddressInfo->Address.Addr [ 5 ]) 2516 && ( pAccess->StationAddress.Addr [ 6 ] == pAddressInfo->Address.Addr [ 6 ]) 2517 && ( pAccess->StationAddress.Addr [ 7 ] == pAddressInfo->Address.Addr [ 7 ]) 2518 && ( pAccess->StationAddress.Addr [ 8 ] == pAddressInfo->Address.Addr [ 8 ]) 2519 && ( pAccess->StationAddress.Addr [ 9 ] == pAddressInfo->Address.Addr [ 9 ]) 2520 && ( pAccess->StationAddress.Addr [ 10 ] == pAddressInfo->Address.Addr [ 10 ]) 2521 && ( pAccess->StationAddress.Addr [ 11 ] == pAddressInfo->Address.Addr [ 11 ]) 2522 && ( pAccess->StationAddress.Addr [ 12 ] == pAddressInfo->Address.Addr [ 12 ]) 2523 && ( pAccess->StationAddress.Addr [ 13 ] == pAddressInfo->Address.Addr [ 13 ]) 2524 && ( pAccess->StationAddress.Addr [ 14 ] == pAddressInfo->Address.Addr [ 14 ]) 2525 && ( pAccess->StationAddress.Addr [ 15 ] == pAddressInfo->Address.Addr [ 15 ])) { 2526 break; 2527 } 2528 } 2529 if ( pIpConfigData->AddressInfoCount > AddressCount ) { 2530 break; 2531 } 2532 2533 // 2534 // The IP address did not match 2535 // 2536 Status = EFI_NOT_STARTED; 2537 break; 2538 } 2539 2540 // 2541 // Free the buffer if necessary 2542 // 2543 if ( NULL != pIpConfigData ) { 2544 FreePool ( pIpConfigData ); 2545 } 2546 2547 // 2548 // Return the IP address status 2549 // 2550 DBG_EXIT_STATUS ( Status ); 2551 return Status; 2552 } 2553 2554 2555 /** 2556 Interface between the socket layer and the network specific 2557 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets 2558 over TCPv6. 2559 **/ 2560 CONST ESL_PROTOCOL_API cEslTcp6Api = { 2561 "TCPv6", 2562 IPPROTO_TCP, 2563 OFFSET_OF ( ESL_PORT, Context.Tcp6.ConfigData ), 2564 OFFSET_OF ( ESL_LAYER, pTcp6List ), 2565 sizeof ( struct sockaddr_in6 ), 2566 sizeof ( struct sockaddr_in6 ), 2567 AF_INET6, 2568 sizeof (((ESL_PACKET *)0 )->Op.Tcp6Rx ), 2569 OFFSET_OF ( ESL_PACKET, Op.Tcp6Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ), 2570 OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Rx.Packet.RxData ), 2571 TRUE, 2572 EADDRINUSE, 2573 EslTcp6Accept, 2574 EslTcp6ConnectPoll, 2575 EslTcp6ConnectStart, 2576 EslTcp6SocketIsConfigured, 2577 EslTcp6LocalAddressGet, 2578 EslTcp6LocalAddressSet, 2579 EslTcp6Listen, 2580 NULL, // OptionGet 2581 NULL, // OptionSet 2582 EslTcp6PacketFree, 2583 EslTcp6PortAllocate, 2584 EslTcp6PortClose, 2585 EslTcp6PortCloseOp, 2586 FALSE, 2587 EslTcp6Receive, 2588 EslTcp6RemoteAddressGet, 2589 EslTcp6RemoteAddressSet, 2590 EslTcp6RxComplete, 2591 EslTcp6RxStart, 2592 EslTcp6TxBuffer, 2593 EslTcp6TxComplete, 2594 EslTcp6TxOobComplete, 2595 (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp6VerifyLocalIpAddress 2596 }; 2597