1 /** @file 2 This library is used to share code between UEFI network stack modules. 3 It provides the helper routines to access TCP service. 4 5 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at<BR> 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include <Uefi.h> 17 18 #include <Library/TcpIoLib.h> 19 #include <Library/BaseLib.h> 20 #include <Library/DebugLib.h> 21 #include <Library/UefiBootServicesTableLib.h> 22 #include <Library/MemoryAllocationLib.h> 23 #include <Library/BaseMemoryLib.h> 24 25 /** 26 The common notify function associated with various TcpIo events. 27 28 @param[in] Event The event signaled. 29 @param[in] Context The context. 30 31 **/ 32 VOID 33 EFIAPI 34 TcpIoCommonNotify ( 35 IN EFI_EVENT Event, 36 IN VOID *Context 37 ) 38 { 39 if ((Event == NULL) || (Context == NULL)) { 40 return ; 41 } 42 43 *((BOOLEAN *) Context) = TRUE; 44 } 45 46 /** 47 The internal function for delay configuring TCP6 when IP6 driver is still in DAD. 48 49 @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance. 50 @param[in] Tcp6ConfigData The Tcp6 configuration data. 51 52 @retval EFI_SUCCESS The operational settings successfully 53 completed. 54 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 55 @retval Others Failed to finish the operation. 56 57 **/ 58 EFI_STATUS 59 TcpIoGetMapping ( 60 IN EFI_TCP6_PROTOCOL *Tcp6, 61 IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData 62 ) 63 { 64 EFI_STATUS Status; 65 EFI_EVENT Event; 66 67 if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) { 68 return EFI_INVALID_PARAMETER; 69 } 70 71 Event = NULL; 72 Status = gBS->CreateEvent ( 73 EVT_TIMER, 74 TPL_CALLBACK, 75 NULL, 76 NULL, 77 &Event 78 ); 79 if (EFI_ERROR (Status)) { 80 goto ON_EXIT; 81 } 82 83 Status = gBS->SetTimer ( 84 Event, 85 TimerRelative, 86 TCP_GET_MAPPING_TIMEOUT 87 ); 88 89 if (EFI_ERROR (Status)) { 90 goto ON_EXIT; 91 } 92 93 while (EFI_ERROR (gBS->CheckEvent (Event))) { 94 95 Tcp6->Poll (Tcp6); 96 97 Status = Tcp6->Configure (Tcp6, Tcp6ConfigData); 98 99 if (!EFI_ERROR (Status)) { 100 break; 101 } 102 } 103 104 ON_EXIT: 105 106 if (Event != NULL) { 107 gBS->CloseEvent (Event); 108 } 109 110 return Status; 111 } 112 113 /** 114 Create a TCP socket with the specified configuration data. 115 116 @param[in] Image The handle of the driver image. 117 @param[in] Controller The handle of the controller. 118 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6. 119 @param[in] ConfigData The Tcp configuration data. 120 @param[out] TcpIo The TcpIo. 121 122 @retval EFI_SUCCESS The TCP socket is created and configured. 123 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 124 @retval EFI_UNSUPPORTED One or more of the control options are not 125 supported in the implementation. 126 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. 127 @retval Others Failed to create the TCP socket or configure it. 128 129 **/ 130 EFI_STATUS 131 EFIAPI 132 TcpIoCreateSocket ( 133 IN EFI_HANDLE Image, 134 IN EFI_HANDLE Controller, 135 IN UINT8 TcpVersion, 136 IN TCP_IO_CONFIG_DATA *ConfigData, 137 OUT TCP_IO *TcpIo 138 ) 139 { 140 EFI_STATUS Status; 141 EFI_EVENT Event; 142 EFI_GUID *ServiceBindingGuid; 143 EFI_GUID *ProtocolGuid; 144 VOID **Interface; 145 EFI_TCP4_OPTION ControlOption; 146 EFI_TCP4_CONFIG_DATA Tcp4ConfigData; 147 EFI_TCP4_ACCESS_POINT *AccessPoint4; 148 EFI_TCP4_PROTOCOL *Tcp4; 149 EFI_TCP6_CONFIG_DATA Tcp6ConfigData; 150 EFI_TCP6_ACCESS_POINT *AccessPoint6; 151 EFI_TCP6_PROTOCOL *Tcp6; 152 EFI_TCP4_RECEIVE_DATA *RxData; 153 154 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) { 155 return EFI_INVALID_PARAMETER; 156 } 157 158 Tcp4 = NULL; 159 Tcp6 = NULL; 160 161 ZeroMem (TcpIo, sizeof (TCP_IO)); 162 163 if (TcpVersion == TCP_VERSION_4) { 164 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; 165 ProtocolGuid = &gEfiTcp4ProtocolGuid; 166 Interface = (VOID **) (&TcpIo->Tcp.Tcp4); 167 } else if (TcpVersion == TCP_VERSION_6) { 168 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; 169 ProtocolGuid = &gEfiTcp6ProtocolGuid; 170 Interface = (VOID **) (&TcpIo->Tcp.Tcp6); 171 } else { 172 return EFI_UNSUPPORTED; 173 } 174 175 TcpIo->TcpVersion = TcpVersion; 176 177 // 178 // Create the TCP child instance and get the TCP protocol. 179 // 180 Status = NetLibCreateServiceChild ( 181 Controller, 182 Image, 183 ServiceBindingGuid, 184 &TcpIo->Handle 185 ); 186 if (EFI_ERROR (Status)) { 187 return Status; 188 } 189 190 Status = gBS->OpenProtocol ( 191 TcpIo->Handle, 192 ProtocolGuid, 193 Interface, 194 Image, 195 Controller, 196 EFI_OPEN_PROTOCOL_BY_DRIVER 197 ); 198 if (EFI_ERROR (Status) || (*Interface == NULL)) { 199 goto ON_ERROR; 200 } 201 202 if (TcpVersion == TCP_VERSION_4) { 203 Tcp4 = TcpIo->Tcp.Tcp4; 204 } else { 205 Tcp6 = TcpIo->Tcp.Tcp6; 206 } 207 208 TcpIo->Image = Image; 209 TcpIo->Controller = Controller; 210 211 // 212 // Set the configuration parameters. 213 // 214 ControlOption.ReceiveBufferSize = 0x200000; 215 ControlOption.SendBufferSize = 0x200000; 216 ControlOption.MaxSynBackLog = 0; 217 ControlOption.ConnectionTimeout = 0; 218 ControlOption.DataRetries = 6; 219 ControlOption.FinTimeout = 0; 220 ControlOption.TimeWaitTimeout = 0; 221 ControlOption.KeepAliveProbes = 4; 222 ControlOption.KeepAliveTime = 0; 223 ControlOption.KeepAliveInterval = 0; 224 ControlOption.EnableNagle = FALSE; 225 ControlOption.EnableTimeStamp = FALSE; 226 ControlOption.EnableWindowScaling = TRUE; 227 ControlOption.EnableSelectiveAck = FALSE; 228 ControlOption.EnablePathMtuDiscovery = FALSE; 229 230 if (TcpVersion == TCP_VERSION_4) { 231 Tcp4ConfigData.TypeOfService = 8; 232 Tcp4ConfigData.TimeToLive = 255; 233 Tcp4ConfigData.ControlOption = &ControlOption; 234 235 AccessPoint4 = &Tcp4ConfigData.AccessPoint; 236 237 ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT)); 238 AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort; 239 AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort; 240 AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag; 241 242 CopyMem ( 243 &AccessPoint4->StationAddress, 244 &ConfigData->Tcp4IoConfigData.LocalIp, 245 sizeof (EFI_IPv4_ADDRESS) 246 ); 247 CopyMem ( 248 &AccessPoint4->SubnetMask, 249 &ConfigData->Tcp4IoConfigData.SubnetMask, 250 sizeof (EFI_IPv4_ADDRESS) 251 ); 252 CopyMem ( 253 &AccessPoint4->RemoteAddress, 254 &ConfigData->Tcp4IoConfigData.RemoteIp, 255 sizeof (EFI_IPv4_ADDRESS) 256 ); 257 258 ASSERT (Tcp4 != NULL); 259 260 // 261 // Configure the TCP4 protocol. 262 // 263 Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData); 264 if (EFI_ERROR (Status)) { 265 goto ON_ERROR; 266 } 267 268 if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) { 269 // 270 // The gateway is not zero. Add the default route manually. 271 // 272 Status = Tcp4->Routes ( 273 Tcp4, 274 FALSE, 275 &mZeroIp4Addr, 276 &mZeroIp4Addr, 277 &ConfigData->Tcp4IoConfigData.Gateway 278 ); 279 if (EFI_ERROR (Status)) { 280 goto ON_ERROR; 281 } 282 } 283 } else { 284 Tcp6ConfigData.TrafficClass = 0; 285 Tcp6ConfigData.HopLimit = 255; 286 Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption; 287 288 AccessPoint6 = &Tcp6ConfigData.AccessPoint; 289 290 ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT)); 291 AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort; 292 AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort; 293 AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag; 294 295 IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp); 296 297 298 ASSERT (Tcp6 != NULL); 299 // 300 // Configure the TCP6 protocol. 301 // 302 Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData); 303 if (Status == EFI_NO_MAPPING) { 304 Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData); 305 } 306 307 if (EFI_ERROR (Status)) { 308 goto ON_ERROR; 309 } 310 } 311 312 // 313 // Create events for variuos asynchronous operations. 314 // 315 Status = gBS->CreateEvent ( 316 EVT_NOTIFY_SIGNAL, 317 TPL_NOTIFY, 318 TcpIoCommonNotify, 319 &TcpIo->IsConnDone, 320 &Event 321 ); 322 if (EFI_ERROR (Status)) { 323 goto ON_ERROR; 324 } 325 326 TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event; 327 328 Status = gBS->CreateEvent ( 329 EVT_NOTIFY_SIGNAL, 330 TPL_NOTIFY, 331 TcpIoCommonNotify, 332 &TcpIo->IsListenDone, 333 &Event 334 ); 335 if (EFI_ERROR (Status)) { 336 goto ON_ERROR; 337 } 338 339 TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event; 340 341 Status = gBS->CreateEvent ( 342 EVT_NOTIFY_SIGNAL, 343 TPL_NOTIFY, 344 TcpIoCommonNotify, 345 &TcpIo->IsTxDone, 346 &Event 347 ); 348 if (EFI_ERROR (Status)) { 349 goto ON_ERROR; 350 } 351 352 TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event; 353 354 355 Status = gBS->CreateEvent ( 356 EVT_NOTIFY_SIGNAL, 357 TPL_NOTIFY, 358 TcpIoCommonNotify, 359 &TcpIo->IsRxDone, 360 &Event 361 ); 362 if (EFI_ERROR (Status)) { 363 goto ON_ERROR; 364 } 365 366 TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event; 367 368 RxData = (EFI_TCP4_RECEIVE_DATA *) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA)); 369 if (RxData == NULL) { 370 Status = EFI_OUT_OF_RESOURCES; 371 goto ON_ERROR; 372 } 373 374 TcpIo->RxToken.Tcp4Token.Packet.RxData = RxData; 375 376 Status = gBS->CreateEvent ( 377 EVT_NOTIFY_SIGNAL, 378 TPL_NOTIFY, 379 TcpIoCommonNotify, 380 &TcpIo->IsCloseDone, 381 &Event 382 ); 383 if (EFI_ERROR (Status)) { 384 goto ON_ERROR; 385 } 386 387 TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event; 388 389 390 return EFI_SUCCESS; 391 392 ON_ERROR: 393 394 TcpIoDestroySocket (TcpIo); 395 396 return Status; 397 } 398 399 /** 400 Destroy the socket. 401 402 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed. 403 404 **/ 405 VOID 406 EFIAPI 407 TcpIoDestroySocket ( 408 IN TCP_IO *TcpIo 409 ) 410 { 411 EFI_EVENT Event; 412 EFI_TCP4_PROTOCOL *Tcp4; 413 EFI_TCP6_PROTOCOL *Tcp6; 414 UINT8 TcpVersion; 415 EFI_GUID *ServiceBindingGuid; 416 EFI_GUID *ProtocolGuid; 417 EFI_HANDLE ChildHandle; 418 419 if (TcpIo == NULL) { 420 return ; 421 } 422 423 TcpVersion = TcpIo->TcpVersion; 424 425 if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) { 426 return ; 427 } 428 429 Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event; 430 431 if (Event != NULL) { 432 gBS->CloseEvent (Event); 433 } 434 435 Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event; 436 437 if (Event != NULL) { 438 gBS->CloseEvent (Event); 439 } 440 441 Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event; 442 443 if (Event != NULL) { 444 gBS->CloseEvent (Event); 445 } 446 447 Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event; 448 449 if (Event != NULL) { 450 gBS->CloseEvent (Event); 451 } 452 453 Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event; 454 455 if (Event != NULL) { 456 gBS->CloseEvent (Event); 457 } 458 459 if (TcpIo->RxToken.Tcp4Token.Packet.RxData != NULL) { 460 FreePool (TcpIo->RxToken.Tcp4Token.Packet.RxData); 461 } 462 463 Tcp4 = NULL; 464 Tcp6 = NULL; 465 466 467 if (TcpVersion == TCP_VERSION_4) { 468 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; 469 ProtocolGuid = &gEfiTcp4ProtocolGuid; 470 Tcp4 = TcpIo->Tcp.Tcp4; 471 if (Tcp4 != NULL) { 472 Tcp4->Configure (Tcp4, NULL); 473 } 474 } else { 475 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; 476 ProtocolGuid = &gEfiTcp6ProtocolGuid; 477 Tcp6 = TcpIo->Tcp.Tcp6; 478 if (Tcp6 != NULL) { 479 Tcp6->Configure (Tcp6, NULL); 480 } 481 } 482 483 if ((Tcp4 != NULL) || (Tcp6 != NULL)) { 484 485 gBS->CloseProtocol ( 486 TcpIo->Handle, 487 ProtocolGuid, 488 TcpIo->Image, 489 TcpIo->Controller 490 ); 491 } 492 493 ChildHandle = NULL; 494 495 if (TcpIo->IsListenDone) { 496 if (TcpVersion == TCP_VERSION_4) { 497 Tcp4 = TcpIo->NewTcp.Tcp4; 498 if (Tcp4 != NULL) { 499 Tcp4->Configure (Tcp4, NULL); 500 ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle; 501 } 502 } else { 503 Tcp6 = TcpIo->NewTcp.Tcp6; 504 if (Tcp6 != NULL) { 505 Tcp6->Configure (Tcp6, NULL); 506 ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle; 507 } 508 } 509 510 if (ChildHandle != NULL) { 511 512 gBS->CloseProtocol ( 513 ChildHandle, 514 ProtocolGuid, 515 TcpIo->Image, 516 TcpIo->Controller 517 ); 518 } 519 } 520 521 NetLibDestroyServiceChild ( 522 TcpIo->Controller, 523 TcpIo->Image, 524 ServiceBindingGuid, 525 TcpIo->Handle 526 ); 527 } 528 529 /** 530 Connect to the other endpoint of the TCP socket. 531 532 @param[in, out] TcpIo The TcpIo wrapping the TCP socket. 533 @param[in] Timeout The time to wait for connection done. 534 535 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket 536 successfully. 537 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the 538 TCP socket in the specified time period. 539 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 540 @retval EFI_UNSUPPORTED One or more of the control options are not 541 supported in the implementation. 542 @retval Others Other errors as indicated. 543 544 **/ 545 EFI_STATUS 546 EFIAPI 547 TcpIoConnect ( 548 IN OUT TCP_IO *TcpIo, 549 IN EFI_EVENT Timeout 550 ) 551 { 552 EFI_TCP4_PROTOCOL *Tcp4; 553 EFI_TCP6_PROTOCOL *Tcp6; 554 EFI_STATUS Status; 555 556 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { 557 return EFI_INVALID_PARAMETER; 558 } 559 560 TcpIo->IsConnDone = FALSE; 561 562 Tcp4 = NULL; 563 Tcp6 = NULL; 564 565 if (TcpIo->TcpVersion == TCP_VERSION_4) { 566 Tcp4 = TcpIo->Tcp.Tcp4; 567 Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token); 568 } else if (TcpIo->TcpVersion == TCP_VERSION_6) { 569 Tcp6 = TcpIo->Tcp.Tcp6; 570 Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token); 571 } else { 572 return EFI_UNSUPPORTED; 573 } 574 575 if (EFI_ERROR (Status)) { 576 return Status; 577 } 578 579 while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) { 580 if (TcpIo->TcpVersion == TCP_VERSION_4) { 581 Tcp4->Poll (Tcp4); 582 } else { 583 Tcp6->Poll (Tcp6); 584 } 585 } 586 587 if (!TcpIo->IsConnDone) { 588 Status = EFI_TIMEOUT; 589 } else { 590 Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status; 591 } 592 593 return Status; 594 } 595 596 /** 597 Accept the incomding request from the other endpoint of the TCP socket. 598 599 @param[in, out] TcpIo The TcpIo wrapping the TCP socket. 600 @param[in] Timeout The time to wait for connection done. 601 602 603 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket 604 successfully. 605 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 606 @retval EFI_UNSUPPORTED One or more of the control options are not 607 supported in the implementation. 608 609 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the 610 TCP socket in the specified time period. 611 @retval Others Other errors as indicated. 612 613 **/ 614 EFI_STATUS 615 EFIAPI 616 TcpIoAccept ( 617 IN OUT TCP_IO *TcpIo, 618 IN EFI_EVENT Timeout 619 ) 620 { 621 EFI_STATUS Status; 622 EFI_GUID *ProtocolGuid; 623 EFI_TCP4_PROTOCOL *Tcp4; 624 EFI_TCP6_PROTOCOL *Tcp6; 625 626 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { 627 return EFI_INVALID_PARAMETER; 628 } 629 630 TcpIo->IsListenDone = FALSE; 631 632 Tcp4 = NULL; 633 Tcp6 = NULL; 634 635 if (TcpIo->TcpVersion == TCP_VERSION_4) { 636 Tcp4 = TcpIo->Tcp.Tcp4; 637 Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token); 638 } else if (TcpIo->TcpVersion == TCP_VERSION_6) { 639 Tcp6 = TcpIo->Tcp.Tcp6; 640 Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token); 641 } else { 642 return EFI_UNSUPPORTED; 643 } 644 645 if (EFI_ERROR (Status)) { 646 return Status; 647 } 648 649 while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) { 650 if (TcpIo->TcpVersion == TCP_VERSION_4) { 651 Tcp4->Poll (Tcp4); 652 } else { 653 Tcp6->Poll (Tcp6); 654 } 655 } 656 657 if (!TcpIo->IsListenDone) { 658 Status = EFI_TIMEOUT; 659 } else { 660 Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status; 661 } 662 663 // 664 // The new TCP instance handle created for the established connection is 665 // in ListenToken. 666 // 667 if (!EFI_ERROR (Status)) { 668 if (TcpIo->TcpVersion == TCP_VERSION_4) { 669 ProtocolGuid = &gEfiTcp4ProtocolGuid; 670 } else { 671 ProtocolGuid = &gEfiTcp6ProtocolGuid; 672 } 673 674 Status = gBS->OpenProtocol ( 675 TcpIo->ListenToken.Tcp4Token.NewChildHandle, 676 ProtocolGuid, 677 (VOID **) (&TcpIo->NewTcp.Tcp4), 678 TcpIo->Image, 679 TcpIo->Controller, 680 EFI_OPEN_PROTOCOL_BY_DRIVER 681 ); 682 683 } 684 685 return Status; 686 } 687 688 /** 689 Reset the socket. 690 691 @param[in, out] TcpIo The TcpIo wrapping the TCP socket. 692 693 **/ 694 VOID 695 EFIAPI 696 TcpIoReset ( 697 IN OUT TCP_IO *TcpIo 698 ) 699 { 700 EFI_TCP4_PROTOCOL *Tcp4; 701 EFI_TCP6_PROTOCOL *Tcp6; 702 EFI_STATUS Status; 703 704 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) { 705 return ; 706 } 707 708 TcpIo->IsCloseDone = FALSE; 709 Tcp4 = NULL; 710 Tcp6 = NULL; 711 712 if (TcpIo->TcpVersion == TCP_VERSION_4) { 713 TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE; 714 Tcp4 = TcpIo->Tcp.Tcp4; 715 Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token); 716 } else if (TcpIo->TcpVersion == TCP_VERSION_6) { 717 TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE; 718 Tcp6 = TcpIo->Tcp.Tcp6; 719 Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token); 720 } else { 721 return ; 722 } 723 724 if (EFI_ERROR (Status)) { 725 return ; 726 } 727 728 while (!TcpIo->IsCloseDone) { 729 if (TcpIo->TcpVersion == TCP_VERSION_4) { 730 Tcp4->Poll (Tcp4); 731 } else { 732 Tcp6->Poll (Tcp6); 733 } 734 } 735 } 736 737 738 /** 739 Transmit the Packet to the other endpoint of the socket. 740 741 @param[in] TcpIo The TcpIo wrapping the TCP socket. 742 @param[in] Packet The packet to transmit. 743 744 @retval EFI_SUCCESS The packet is trasmitted. 745 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 746 @retval EFI_UNSUPPORTED One or more of the control options are not 747 supported in the implementation. 748 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. 749 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. 750 @retval Others Other errors as indicated. 751 752 **/ 753 EFI_STATUS 754 EFIAPI 755 TcpIoTransmit ( 756 IN TCP_IO *TcpIo, 757 IN NET_BUF *Packet 758 ) 759 { 760 EFI_STATUS Status; 761 VOID *Data; 762 EFI_TCP4_PROTOCOL *Tcp4; 763 EFI_TCP6_PROTOCOL *Tcp6; 764 UINTN Size; 765 766 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) { 767 return EFI_INVALID_PARAMETER; 768 } 769 770 if (TcpIo->TcpVersion == TCP_VERSION_4) { 771 772 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + 773 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA); 774 } else if (TcpIo->TcpVersion == TCP_VERSION_6) { 775 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) + 776 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA); 777 } else { 778 return EFI_UNSUPPORTED; 779 } 780 781 Data = AllocatePool (Size); 782 if (Data == NULL) { 783 return EFI_OUT_OF_RESOURCES; 784 } 785 786 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE; 787 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE; 788 ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize; 789 790 // 791 // Build the fragment table. 792 // 793 ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum; 794 795 NetbufBuildExt ( 796 Packet, 797 (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0], 798 &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount 799 ); 800 801 Tcp4 = NULL; 802 Tcp6 = NULL; 803 Status = EFI_DEVICE_ERROR; 804 805 // 806 // Trasnmit the packet. 807 // 808 if (TcpIo->TcpVersion == TCP_VERSION_4) { 809 TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data; 810 Tcp4 = TcpIo->Tcp.Tcp4; 811 if (TcpIo->IsListenDone) { 812 Tcp4 = TcpIo->NewTcp.Tcp4; 813 } 814 815 if (Tcp4 == NULL) { 816 goto ON_EXIT; 817 } 818 819 Status = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token); 820 } else { 821 TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data; 822 Tcp6 = TcpIo->Tcp.Tcp6; 823 if (TcpIo->IsListenDone) { 824 Tcp6 = TcpIo->NewTcp.Tcp6; 825 } 826 827 if (Tcp6 == NULL) { 828 goto ON_EXIT; 829 } 830 831 Status = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token); 832 } 833 834 if (EFI_ERROR (Status)) { 835 goto ON_EXIT; 836 } 837 838 while (!TcpIo->IsTxDone) { 839 if (TcpIo->TcpVersion == TCP_VERSION_4) { 840 Tcp4->Poll (Tcp4); 841 } else { 842 Tcp6->Poll (Tcp6); 843 } 844 } 845 846 TcpIo->IsTxDone = FALSE; 847 Status = TcpIo->TxToken.Tcp4Token.CompletionToken.Status; 848 849 ON_EXIT: 850 851 FreePool (Data); 852 853 return Status; 854 } 855 856 /** 857 Receive data from the socket. 858 859 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed. 860 @param[in] Packet The buffer to hold the data copy from the socket rx buffer. 861 @param[in] AsyncMode Is this receive asyncronous or not. 862 @param[in] Timeout The time to wait for receiving the amount of data the Packet 863 can hold. 864 865 @retval EFI_SUCCESS The required amount of data is received from the socket. 866 @retval EFI_INVALID_PARAMETER One or more parameters are invalid. 867 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. 868 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery. 869 @retval EFI_TIMEOUT Failed to receive the required amount of data in the 870 specified time period. 871 @retval Others Other errors as indicated. 872 873 **/ 874 EFI_STATUS 875 EFIAPI 876 TcpIoReceive ( 877 IN OUT TCP_IO *TcpIo, 878 IN NET_BUF *Packet, 879 IN BOOLEAN AsyncMode, 880 IN EFI_EVENT Timeout 881 ) 882 { 883 EFI_TCP4_PROTOCOL *Tcp4; 884 EFI_TCP6_PROTOCOL *Tcp6; 885 EFI_TCP4_RECEIVE_DATA *RxData; 886 EFI_STATUS Status; 887 NET_FRAGMENT *Fragment; 888 UINT32 FragmentCount; 889 UINT32 CurrentFragment; 890 891 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) { 892 return EFI_INVALID_PARAMETER; 893 } 894 895 RxData = TcpIo->RxToken.Tcp4Token.Packet.RxData; 896 if (RxData == NULL) { 897 return EFI_INVALID_PARAMETER; 898 } 899 900 Tcp4 = NULL; 901 Tcp6 = NULL; 902 903 if (TcpIo->TcpVersion == TCP_VERSION_4) { 904 Tcp4 = TcpIo->Tcp.Tcp4; 905 906 if (TcpIo->IsListenDone) { 907 Tcp4 = TcpIo->NewTcp.Tcp4; 908 } 909 910 if (Tcp4 == NULL) { 911 return EFI_DEVICE_ERROR; 912 } 913 914 } else if (TcpIo->TcpVersion == TCP_VERSION_6) { 915 Tcp6 = TcpIo->Tcp.Tcp6; 916 917 if (TcpIo->IsListenDone) { 918 Tcp6 = TcpIo->NewTcp.Tcp6; 919 } 920 921 if (Tcp6 == NULL) { 922 return EFI_DEVICE_ERROR; 923 } 924 925 } else { 926 return EFI_UNSUPPORTED; 927 } 928 929 FragmentCount = Packet->BlockOpNum; 930 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT)); 931 if (Fragment == NULL) { 932 Status = EFI_OUT_OF_RESOURCES; 933 goto ON_EXIT; 934 } 935 // 936 // Build the fragment table. 937 // 938 NetbufBuildExt (Packet, Fragment, &FragmentCount); 939 940 RxData->FragmentCount = 1; 941 CurrentFragment = 0; 942 Status = EFI_SUCCESS; 943 944 while (CurrentFragment < FragmentCount) { 945 RxData->DataLength = Fragment[CurrentFragment].Len; 946 RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len; 947 RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk; 948 949 if (TcpIo->TcpVersion == TCP_VERSION_4) { 950 Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token); 951 } else { 952 Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token); 953 } 954 955 if (EFI_ERROR (Status)) { 956 goto ON_EXIT; 957 } 958 959 while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) { 960 // 961 // Poll until some data is received or an error occurs. 962 // 963 if (TcpIo->TcpVersion == TCP_VERSION_4) { 964 Tcp4->Poll (Tcp4); 965 } else { 966 Tcp6->Poll (Tcp6); 967 } 968 } 969 970 if (!TcpIo->IsRxDone) { 971 // 972 // Timeout occurs, cancel the receive request. 973 // 974 if (TcpIo->TcpVersion == TCP_VERSION_4) { 975 Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken); 976 } else { 977 Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken); 978 } 979 980 Status = EFI_TIMEOUT; 981 goto ON_EXIT; 982 } else { 983 TcpIo->IsRxDone = FALSE; 984 } 985 986 Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status; 987 988 if (EFI_ERROR (Status)) { 989 goto ON_EXIT; 990 } 991 992 Fragment[CurrentFragment].Len -= RxData->FragmentTable[0].FragmentLength; 993 if (Fragment[CurrentFragment].Len == 0) { 994 CurrentFragment++; 995 } else { 996 Fragment[CurrentFragment].Bulk += RxData->FragmentTable[0].FragmentLength; 997 } 998 } 999 1000 ON_EXIT: 1001 1002 if (Fragment != NULL) { 1003 FreePool (Fragment); 1004 } 1005 1006 return Status; 1007 } 1008