1 /** @file 2 IpIo Library. 3 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> 5 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR> 6 SPDX-License-Identifier: BSD-2-Clause-Patent 7 **/ 8 9 #include <Uefi.h> 10 11 #include <Protocol/Udp4.h> 12 13 #include <Library/IpIoLib.h> 14 #include <Library/BaseLib.h> 15 #include <Library/DebugLib.h> 16 #include <Library/BaseMemoryLib.h> 17 #include <Library/UefiBootServicesTableLib.h> 18 #include <Library/MemoryAllocationLib.h> 19 #include <Library/DpcLib.h> 20 21 22 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList = { 23 &mActiveIpIoList, 24 &mActiveIpIoList 25 }; 26 27 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData = { 28 EFI_IP_PROTO_UDP, 29 FALSE, 30 TRUE, 31 FALSE, 32 FALSE, 33 FALSE, 34 {{0, 0, 0, 0}}, 35 {{0, 0, 0, 0}}, 36 0, 37 255, 38 FALSE, 39 FALSE, 40 0, 41 0 42 }; 43 44 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData = { 45 EFI_IP_PROTO_UDP, 46 FALSE, 47 TRUE, 48 FALSE, 49 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 50 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, 51 0, 52 255, 53 0, 54 0, 55 0 56 }; 57 58 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap[10] = { 59 {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET 60 {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST 61 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PROTOCOL 62 {TRUE, TRUE }, // ICMP_ERR_UNREACH_PORT 63 {TRUE, TRUE }, // ICMP_ERR_MSGSIZE 64 {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL 65 {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS 66 {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS 67 {FALSE, FALSE}, // ICMP_ERR_QUENCH 68 {FALSE, TRUE } // ICMP_ERR_PARAMPROB 69 }; 70 71 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap[10] = { 72 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET 73 {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST 74 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL 75 {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PORT 76 {TRUE, TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG 77 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT 78 {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS 79 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER 80 {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER 81 {FALSE, TRUE} // ICMP6_ERR_PARAMPROB_IPV6OPTION 82 }; 83 84 85 /** 86 Notify function for IP transmit token. 87 88 @param[in] Context The context passed in by the event notifier. 89 90 **/ 91 VOID 92 EFIAPI 93 IpIoTransmitHandlerDpc ( 94 IN VOID *Context 95 ); 96 97 98 /** 99 Notify function for IP transmit token. 100 101 @param[in] Event The event signaled. 102 @param[in] Context The context passed in by the event notifier. 103 104 **/ 105 VOID 106 EFIAPI 107 IpIoTransmitHandler ( 108 IN EFI_EVENT Event, 109 IN VOID *Context 110 ); 111 112 113 /** 114 This function create an IP child ,open the IP protocol, and return the opened 115 IP protocol as Interface. 116 117 @param[in] ControllerHandle The controller handle. 118 @param[in] ImageHandle The image handle. 119 @param[in] ChildHandle Pointer to the buffer to save the IP child handle. 120 @param[in] IpVersion The version of the IP protocol to use, either 121 IPv4 or IPv6. 122 @param[out] Interface Pointer used to get the IP protocol interface. 123 124 @retval EFI_SUCCESS The IP child is created and the IP protocol 125 interface is retrieved. 126 @retval EFI_UNSUPPORTED Unsupported IpVersion. 127 @retval Others The required operation failed. 128 129 **/ 130 EFI_STATUS 131 IpIoCreateIpChildOpenProtocol ( 132 IN EFI_HANDLE ControllerHandle, 133 IN EFI_HANDLE ImageHandle, 134 IN EFI_HANDLE *ChildHandle, 135 IN UINT8 IpVersion, 136 OUT VOID **Interface 137 ) 138 { 139 EFI_STATUS Status; 140 EFI_GUID *ServiceBindingGuid; 141 EFI_GUID *IpProtocolGuid; 142 143 if (IpVersion == IP_VERSION_4) { 144 ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid; 145 IpProtocolGuid = &gEfiIp4ProtocolGuid; 146 } else if (IpVersion == IP_VERSION_6){ 147 ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid; 148 IpProtocolGuid = &gEfiIp6ProtocolGuid; 149 } else { 150 return EFI_UNSUPPORTED; 151 } 152 153 // 154 // Create an IP child. 155 // 156 Status = NetLibCreateServiceChild ( 157 ControllerHandle, 158 ImageHandle, 159 ServiceBindingGuid, 160 ChildHandle 161 ); 162 if (EFI_ERROR (Status)) { 163 return Status; 164 } 165 166 // 167 // Open the IP protocol installed on the *ChildHandle. 168 // 169 Status = gBS->OpenProtocol ( 170 *ChildHandle, 171 IpProtocolGuid, 172 Interface, 173 ImageHandle, 174 ControllerHandle, 175 EFI_OPEN_PROTOCOL_BY_DRIVER 176 ); 177 if (EFI_ERROR (Status)) { 178 // 179 // On failure, destroy the IP child. 180 // 181 NetLibDestroyServiceChild ( 182 ControllerHandle, 183 ImageHandle, 184 ServiceBindingGuid, 185 *ChildHandle 186 ); 187 } 188 189 return Status; 190 } 191 192 193 /** 194 This function close the previously opened IP protocol and destroy the IP child. 195 196 @param[in] ControllerHandle The controller handle. 197 @param[in] ImageHandle The image handle. 198 @param[in] ChildHandle The child handle of the IP child. 199 @param[in] IpVersion The version of the IP protocol to use, either 200 IPv4 or IPv6. 201 202 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child 203 is destroyed. 204 @retval EFI_UNSUPPORTED Unsupported IpVersion. 205 @retval Others The required operation failed. 206 207 **/ 208 EFI_STATUS 209 IpIoCloseProtocolDestroyIpChild ( 210 IN EFI_HANDLE ControllerHandle, 211 IN EFI_HANDLE ImageHandle, 212 IN EFI_HANDLE ChildHandle, 213 IN UINT8 IpVersion 214 ) 215 { 216 EFI_STATUS Status; 217 EFI_GUID *ServiceBindingGuid; 218 EFI_GUID *IpProtocolGuid; 219 220 if (IpVersion == IP_VERSION_4) { 221 ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid; 222 IpProtocolGuid = &gEfiIp4ProtocolGuid; 223 } else if (IpVersion == IP_VERSION_6) { 224 ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid; 225 IpProtocolGuid = &gEfiIp6ProtocolGuid; 226 } else { 227 return EFI_UNSUPPORTED; 228 } 229 230 // 231 // Close the previously opened IP protocol. 232 // 233 Status = gBS->CloseProtocol ( 234 ChildHandle, 235 IpProtocolGuid, 236 ImageHandle, 237 ControllerHandle 238 ); 239 if (EFI_ERROR (Status)) { 240 return Status; 241 } 242 243 // 244 // Destroy the IP child. 245 // 246 return NetLibDestroyServiceChild ( 247 ControllerHandle, 248 ImageHandle, 249 ServiceBindingGuid, 250 ChildHandle 251 ); 252 } 253 254 /** 255 This function handles ICMPv4 packets. It is the worker function of 256 IpIoIcmpHandler. 257 258 @param[in] IpIo Pointer to the IP_IO instance. 259 @param[in, out] Pkt Pointer to the ICMPv4 packet. 260 @param[in] Session Pointer to the net session of this ICMPv4 packet. 261 262 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully. 263 @retval EFI_ABORTED This type of ICMPv4 packet is not supported. 264 265 **/ 266 EFI_STATUS 267 IpIoIcmpv4Handler ( 268 IN IP_IO *IpIo, 269 IN OUT NET_BUF *Pkt, 270 IN EFI_NET_SESSION_DATA *Session 271 ) 272 { 273 IP4_ICMP_ERROR_HEAD *IcmpHdr; 274 EFI_IP4_HEADER *IpHdr; 275 UINT8 IcmpErr; 276 UINT8 *PayLoadHdr; 277 UINT8 Type; 278 UINT8 Code; 279 UINT32 TrimBytes; 280 281 ASSERT (IpIo != NULL); 282 ASSERT (Pkt != NULL); 283 ASSERT (Session != NULL); 284 ASSERT (IpIo->IpVersion == IP_VERSION_4); 285 286 // 287 // Check the ICMP packet length. 288 // 289 if (Pkt->TotalSize < sizeof (IP4_ICMP_ERROR_HEAD)) { 290 return EFI_ABORTED; 291 } 292 293 IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD); 294 IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead); 295 296 if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) { 297 298 return EFI_ABORTED; 299 } 300 301 Type = IcmpHdr->Head.Type; 302 Code = IcmpHdr->Head.Code; 303 304 // 305 // Analyze the ICMP Error in this ICMP pkt 306 // 307 switch (Type) { 308 case ICMP_TYPE_UNREACH: 309 switch (Code) { 310 case ICMP_CODE_UNREACH_NET: 311 case ICMP_CODE_UNREACH_HOST: 312 case ICMP_CODE_UNREACH_PROTOCOL: 313 case ICMP_CODE_UNREACH_PORT: 314 case ICMP_CODE_UNREACH_SRCFAIL: 315 IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code); 316 317 break; 318 319 case ICMP_CODE_UNREACH_NEEDFRAG: 320 IcmpErr = ICMP_ERR_MSGSIZE; 321 322 break; 323 324 case ICMP_CODE_UNREACH_NET_UNKNOWN: 325 case ICMP_CODE_UNREACH_NET_PROHIB: 326 case ICMP_CODE_UNREACH_TOSNET: 327 IcmpErr = ICMP_ERR_UNREACH_NET; 328 329 break; 330 331 case ICMP_CODE_UNREACH_HOST_UNKNOWN: 332 case ICMP_CODE_UNREACH_ISOLATED: 333 case ICMP_CODE_UNREACH_HOST_PROHIB: 334 case ICMP_CODE_UNREACH_TOSHOST: 335 IcmpErr = ICMP_ERR_UNREACH_HOST; 336 337 break; 338 339 default: 340 return EFI_ABORTED; 341 } 342 343 break; 344 345 case ICMP_TYPE_TIMXCEED: 346 if (Code > 1) { 347 return EFI_ABORTED; 348 } 349 350 IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS); 351 352 break; 353 354 case ICMP_TYPE_PARAMPROB: 355 if (Code > 1) { 356 return EFI_ABORTED; 357 } 358 359 IcmpErr = ICMP_ERR_PARAMPROB; 360 361 break; 362 363 case ICMP_TYPE_SOURCEQUENCH: 364 if (Code != 0) { 365 return EFI_ABORTED; 366 } 367 368 IcmpErr = ICMP_ERR_QUENCH; 369 370 break; 371 372 default: 373 return EFI_ABORTED; 374 } 375 376 // 377 // Notify user the ICMP pkt only containing payload except 378 // IP and ICMP header 379 // 380 PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr)); 381 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr); 382 383 NetbufTrim (Pkt, TrimBytes, TRUE); 384 385 // 386 // If the input packet has invalid format, and TrimBytes is larger than 387 // the packet size, the NetbufTrim might trim the packet to zero. 388 // 389 if (Pkt->TotalSize != 0) { 390 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext); 391 } 392 393 return EFI_SUCCESS; 394 } 395 396 /** 397 This function handles ICMPv6 packets. It is the worker function of 398 IpIoIcmpHandler. 399 400 @param[in] IpIo Pointer to the IP_IO instance. 401 @param[in, out] Pkt Pointer to the ICMPv6 packet. 402 @param[in] Session Pointer to the net session of this ICMPv6 packet. 403 404 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully. 405 @retval EFI_ABORTED This type of ICMPv6 packet is not supported. 406 407 **/ 408 EFI_STATUS 409 IpIoIcmpv6Handler ( 410 IN IP_IO *IpIo, 411 IN OUT NET_BUF *Pkt, 412 IN EFI_NET_SESSION_DATA *Session 413 ) 414 { 415 IP6_ICMP_ERROR_HEAD *IcmpHdr; 416 EFI_IP6_HEADER *IpHdr; 417 UINT8 IcmpErr; 418 UINT8 *PayLoadHdr; 419 UINT8 Type; 420 UINT8 Code; 421 UINT8 NextHeader; 422 UINT32 TrimBytes; 423 BOOLEAN Flag; 424 425 ASSERT (IpIo != NULL); 426 ASSERT (Pkt != NULL); 427 ASSERT (Session != NULL); 428 ASSERT (IpIo->IpVersion == IP_VERSION_6); 429 430 // 431 // Check the ICMPv6 packet length. 432 // 433 if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) { 434 435 return EFI_ABORTED; 436 } 437 438 IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD); 439 Type = IcmpHdr->Head.Type; 440 Code = IcmpHdr->Head.Code; 441 442 // 443 // Analyze the ICMPv6 Error in this ICMPv6 packet 444 // 445 switch (Type) { 446 case ICMP_V6_DEST_UNREACHABLE: 447 switch (Code) { 448 case ICMP_V6_NO_ROUTE_TO_DEST: 449 case ICMP_V6_BEYOND_SCOPE: 450 case ICMP_V6_ROUTE_REJECTED: 451 IcmpErr = ICMP6_ERR_UNREACH_NET; 452 453 break; 454 455 case ICMP_V6_COMM_PROHIBITED: 456 case ICMP_V6_ADDR_UNREACHABLE: 457 case ICMP_V6_SOURCE_ADDR_FAILED: 458 IcmpErr = ICMP6_ERR_UNREACH_HOST; 459 460 break; 461 462 case ICMP_V6_PORT_UNREACHABLE: 463 IcmpErr = ICMP6_ERR_UNREACH_PORT; 464 465 break; 466 467 default: 468 return EFI_ABORTED; 469 } 470 471 break; 472 473 case ICMP_V6_PACKET_TOO_BIG: 474 if (Code >= 1) { 475 return EFI_ABORTED; 476 } 477 478 IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG; 479 480 break; 481 482 case ICMP_V6_TIME_EXCEEDED: 483 if (Code > 1) { 484 return EFI_ABORTED; 485 } 486 487 IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code); 488 489 break; 490 491 case ICMP_V6_PARAMETER_PROBLEM: 492 if (Code > 3) { 493 return EFI_ABORTED; 494 } 495 496 IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code); 497 498 break; 499 500 default: 501 502 return EFI_ABORTED; 503 } 504 505 // 506 // Notify user the ICMPv6 packet only containing payload except 507 // IPv6 basic header, extension header and ICMP header 508 // 509 510 IpHdr = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead); 511 NextHeader = IpHdr->NextHeader; 512 PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD)); 513 Flag = TRUE; 514 515 do { 516 switch (NextHeader) { 517 case EFI_IP_PROTO_UDP: 518 case EFI_IP_PROTO_TCP: 519 case EFI_IP_PROTO_ICMP: 520 case IP6_NO_NEXT_HEADER: 521 Flag = FALSE; 522 523 break; 524 525 case IP6_HOP_BY_HOP: 526 case IP6_DESTINATION: 527 // 528 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including 529 // the first 8 octets. 530 // 531 NextHeader = *(PayLoadHdr); 532 PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8); 533 534 break; 535 536 case IP6_FRAGMENT: 537 // 538 // The Fragment Header Length is 8 octets. 539 // 540 NextHeader = *(PayLoadHdr); 541 PayLoadHdr = (UINT8 *) (PayLoadHdr + 8); 542 543 break; 544 545 default: 546 547 return EFI_ABORTED; 548 } 549 } while (Flag); 550 551 TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr); 552 553 NetbufTrim (Pkt, TrimBytes, TRUE); 554 555 // 556 // If the input packet has invalid format, and TrimBytes is larger than 557 // the packet size, the NetbufTrim might trim the packet to zero. 558 // 559 if (Pkt->TotalSize != 0) { 560 IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext); 561 } 562 563 return EFI_SUCCESS; 564 } 565 566 /** 567 This function handles ICMP packets. 568 569 @param[in] IpIo Pointer to the IP_IO instance. 570 @param[in, out] Pkt Pointer to the ICMP packet. 571 @param[in] Session Pointer to the net session of this ICMP packet. 572 573 @retval EFI_SUCCESS The ICMP packet is handled successfully. 574 @retval EFI_ABORTED This type of ICMP packet is not supported. 575 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported. 576 577 **/ 578 EFI_STATUS 579 IpIoIcmpHandler ( 580 IN IP_IO *IpIo, 581 IN OUT NET_BUF *Pkt, 582 IN EFI_NET_SESSION_DATA *Session 583 ) 584 { 585 586 if (IpIo->IpVersion == IP_VERSION_4) { 587 588 return IpIoIcmpv4Handler (IpIo, Pkt, Session); 589 590 } else if (IpIo->IpVersion == IP_VERSION_6) { 591 592 return IpIoIcmpv6Handler (IpIo, Pkt, Session); 593 594 } else { 595 596 return EFI_UNSUPPORTED; 597 } 598 } 599 600 601 /** 602 Free function for receive token of IP_IO. It is used to 603 signal the recycle event to notify IP to recycle the 604 data buffer. 605 606 @param[in] Event The event to be signaled. 607 608 **/ 609 VOID 610 EFIAPI 611 IpIoExtFree ( 612 IN VOID *Event 613 ) 614 { 615 gBS->SignalEvent ((EFI_EVENT) Event); 616 } 617 618 619 /** 620 Create a send entry to wrap a packet before sending 621 out it through IP. 622 623 @param[in, out] IpIo Pointer to the IP_IO instance. 624 @param[in, out] Pkt Pointer to the packet. 625 @param[in] Sender Pointer to the IP sender. 626 @param[in] Context Pointer to the context. 627 @param[in] NotifyData Pointer to the notify data. 628 @param[in] Dest Pointer to the destination IP address. 629 @param[in] Override Pointer to the overridden IP_IO data. 630 631 @return Pointer to the data structure created to wrap the packet. If any error occurs, 632 then return NULL. 633 634 **/ 635 IP_IO_SEND_ENTRY * 636 IpIoCreateSndEntry ( 637 IN OUT IP_IO *IpIo, 638 IN OUT NET_BUF *Pkt, 639 IN IP_IO_IP_PROTOCOL Sender, 640 IN VOID *Context OPTIONAL, 641 IN VOID *NotifyData OPTIONAL, 642 IN EFI_IP_ADDRESS *Dest OPTIONAL, 643 IN IP_IO_OVERRIDE *Override 644 ) 645 { 646 IP_IO_SEND_ENTRY *SndEntry; 647 EFI_EVENT Event; 648 EFI_STATUS Status; 649 NET_FRAGMENT *ExtFragment; 650 UINT32 FragmentCount; 651 IP_IO_OVERRIDE *OverrideData; 652 IP_IO_IP_TX_DATA *TxData; 653 EFI_IP4_TRANSMIT_DATA *Ip4TxData; 654 EFI_IP6_TRANSMIT_DATA *Ip6TxData; 655 656 if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) { 657 return NULL; 658 } 659 660 Event = NULL; 661 TxData = NULL; 662 OverrideData = NULL; 663 664 // 665 // Allocate resource for SndEntry 666 // 667 SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY)); 668 if (NULL == SndEntry) { 669 return NULL; 670 } 671 672 Status = gBS->CreateEvent ( 673 EVT_NOTIFY_SIGNAL, 674 TPL_NOTIFY, 675 IpIoTransmitHandler, 676 SndEntry, 677 &Event 678 ); 679 if (EFI_ERROR (Status)) { 680 goto ON_ERROR; 681 } 682 683 FragmentCount = Pkt->BlockOpNum; 684 685 // 686 // Allocate resource for TxData 687 // 688 TxData = (IP_IO_IP_TX_DATA *) AllocatePool ( 689 sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1) 690 ); 691 692 if (NULL == TxData) { 693 goto ON_ERROR; 694 } 695 696 // 697 // Build a fragment table to contain the fragments in the packet. 698 // 699 if (IpIo->IpVersion == IP_VERSION_4) { 700 ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable; 701 } else { 702 ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable; 703 } 704 705 NetbufBuildExt (Pkt, ExtFragment, &FragmentCount); 706 707 708 // 709 // Allocate resource for OverrideData if needed 710 // 711 if (NULL != Override) { 712 713 OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override); 714 if (NULL == OverrideData) { 715 goto ON_ERROR; 716 } 717 } 718 719 // 720 // Set other fields of TxData except the fragment table 721 // 722 if (IpIo->IpVersion == IP_VERSION_4) { 723 724 Ip4TxData = &TxData->Ip4TxData; 725 726 IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest); 727 728 Ip4TxData->OverrideData = &OverrideData->Ip4OverrideData; 729 Ip4TxData->OptionsLength = 0; 730 Ip4TxData->OptionsBuffer = NULL; 731 Ip4TxData->TotalDataLength = Pkt->TotalSize; 732 Ip4TxData->FragmentCount = FragmentCount; 733 734 // 735 // Set the fields of SndToken 736 // 737 SndEntry->SndToken.Ip4Token.Event = Event; 738 SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData; 739 } else { 740 741 Ip6TxData = &TxData->Ip6TxData; 742 743 if (Dest != NULL) { 744 CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS)); 745 } else { 746 ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)); 747 } 748 749 Ip6TxData->OverrideData = &OverrideData->Ip6OverrideData; 750 Ip6TxData->DataLength = Pkt->TotalSize; 751 Ip6TxData->FragmentCount = FragmentCount; 752 Ip6TxData->ExtHdrsLength = 0; 753 Ip6TxData->ExtHdrs = NULL; 754 755 // 756 // Set the fields of SndToken 757 // 758 SndEntry->SndToken.Ip6Token.Event = Event; 759 SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData; 760 } 761 762 // 763 // Set the fields of SndEntry 764 // 765 SndEntry->IpIo = IpIo; 766 SndEntry->Ip = Sender; 767 SndEntry->Context = Context; 768 SndEntry->NotifyData = NotifyData; 769 770 SndEntry->Pkt = Pkt; 771 NET_GET_REF (Pkt); 772 773 InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry); 774 775 return SndEntry; 776 777 ON_ERROR: 778 779 if (OverrideData != NULL) { 780 FreePool (OverrideData); 781 } 782 783 if (TxData != NULL) { 784 FreePool (TxData); 785 } 786 787 if (SndEntry != NULL) { 788 FreePool (SndEntry); 789 } 790 791 if (Event != NULL) { 792 gBS->CloseEvent (Event); 793 } 794 795 return NULL; 796 } 797 798 799 /** 800 Destroy the SndEntry. 801 802 This function pairs with IpIoCreateSndEntry(). 803 804 @param[in] SndEntry Pointer to the send entry to be destroyed. 805 806 **/ 807 VOID 808 IpIoDestroySndEntry ( 809 IN IP_IO_SEND_ENTRY *SndEntry 810 ) 811 { 812 EFI_EVENT Event; 813 IP_IO_IP_TX_DATA *TxData; 814 IP_IO_OVERRIDE *Override; 815 816 if (SndEntry->IpIo->IpVersion == IP_VERSION_4) { 817 Event = SndEntry->SndToken.Ip4Token.Event; 818 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData; 819 Override = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData; 820 } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) { 821 Event = SndEntry->SndToken.Ip6Token.Event; 822 TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData; 823 Override = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData; 824 } else { 825 return ; 826 } 827 828 gBS->CloseEvent (Event); 829 830 FreePool (TxData); 831 832 if (NULL != Override) { 833 FreePool (Override); 834 } 835 836 NetbufFree (SndEntry->Pkt); 837 838 RemoveEntryList (&SndEntry->Entry); 839 840 FreePool (SndEntry); 841 } 842 843 844 /** 845 Notify function for IP transmit token. 846 847 @param[in] Context The context passed in by the event notifier. 848 849 **/ 850 VOID 851 EFIAPI 852 IpIoTransmitHandlerDpc ( 853 IN VOID *Context 854 ) 855 { 856 IP_IO *IpIo; 857 IP_IO_SEND_ENTRY *SndEntry; 858 EFI_STATUS Status; 859 860 SndEntry = (IP_IO_SEND_ENTRY *) Context; 861 862 IpIo = SndEntry->IpIo; 863 864 if (IpIo->IpVersion == IP_VERSION_4) { 865 Status = SndEntry->SndToken.Ip4Token.Status; 866 } else if (IpIo->IpVersion == IP_VERSION_6){ 867 Status = SndEntry->SndToken.Ip6Token.Status; 868 } else { 869 return ; 870 } 871 872 if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) { 873 IpIo->PktSentNotify ( 874 Status, 875 SndEntry->Context, 876 SndEntry->Ip, 877 SndEntry->NotifyData 878 ); 879 } 880 881 IpIoDestroySndEntry (SndEntry); 882 } 883 884 885 /** 886 Notify function for IP transmit token. 887 888 @param[in] Event The event signaled. 889 @param[in] Context The context passed in by the event notifier. 890 891 **/ 892 VOID 893 EFIAPI 894 IpIoTransmitHandler ( 895 IN EFI_EVENT Event, 896 IN VOID *Context 897 ) 898 { 899 // 900 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK 901 // 902 QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context); 903 } 904 905 906 /** 907 The dummy handler for the dummy IP receive token. 908 909 @param[in] Context The context passed in by the event notifier. 910 911 **/ 912 VOID 913 EFIAPI 914 IpIoDummyHandlerDpc ( 915 IN VOID *Context 916 ) 917 { 918 IP_IO_IP_INFO *IpInfo; 919 EFI_STATUS Status; 920 EFI_EVENT RecycleEvent; 921 922 IpInfo = (IP_IO_IP_INFO *) Context; 923 924 if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) { 925 return ; 926 } 927 928 RecycleEvent = NULL; 929 930 if (IpInfo->IpVersion == IP_VERSION_4) { 931 Status = IpInfo->DummyRcvToken.Ip4Token.Status; 932 933 if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) { 934 RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal; 935 } 936 } else { 937 Status = IpInfo->DummyRcvToken.Ip6Token.Status; 938 939 if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) { 940 RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal; 941 } 942 } 943 944 945 946 if (EFI_ABORTED == Status) { 947 // 948 // The reception is actively aborted by the consumer, directly return. 949 // 950 return; 951 } else if (EFI_SUCCESS == Status) { 952 // 953 // Recycle the RxData. 954 // 955 ASSERT (RecycleEvent != NULL); 956 957 gBS->SignalEvent (RecycleEvent); 958 } 959 960 // 961 // Continue the receive. 962 // 963 if (IpInfo->IpVersion == IP_VERSION_4) { 964 IpInfo->Ip.Ip4->Receive ( 965 IpInfo->Ip.Ip4, 966 &IpInfo->DummyRcvToken.Ip4Token 967 ); 968 } else { 969 IpInfo->Ip.Ip6->Receive ( 970 IpInfo->Ip.Ip6, 971 &IpInfo->DummyRcvToken.Ip6Token 972 ); 973 } 974 } 975 976 977 /** 978 This function add IpIoDummyHandlerDpc to the end of the DPC queue. 979 980 @param[in] Event The event signaled. 981 @param[in] Context The context passed in by the event notifier. 982 983 **/ 984 VOID 985 EFIAPI 986 IpIoDummyHandler ( 987 IN EFI_EVENT Event, 988 IN VOID *Context 989 ) 990 { 991 // 992 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK 993 // 994 QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context); 995 } 996 997 998 /** 999 Notify function for the IP receive token, used to process 1000 the received IP packets. 1001 1002 @param[in] Context The context passed in by the event notifier. 1003 1004 **/ 1005 VOID 1006 EFIAPI 1007 IpIoListenHandlerDpc ( 1008 IN VOID *Context 1009 ) 1010 { 1011 IP_IO *IpIo; 1012 EFI_STATUS Status; 1013 IP_IO_IP_RX_DATA *RxData; 1014 EFI_NET_SESSION_DATA Session; 1015 NET_BUF *Pkt; 1016 1017 IpIo = (IP_IO *) Context; 1018 1019 if (IpIo->IpVersion == IP_VERSION_4) { 1020 Status = IpIo->RcvToken.Ip4Token.Status; 1021 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData; 1022 } else if (IpIo->IpVersion == IP_VERSION_6) { 1023 Status = IpIo->RcvToken.Ip6Token.Status; 1024 RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData; 1025 } else { 1026 return; 1027 } 1028 1029 if (EFI_ABORTED == Status) { 1030 // 1031 // The reception is actively aborted by the consumer, directly return. 1032 // 1033 return; 1034 } 1035 1036 if ((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) { 1037 // 1038 // Only process the normal packets and the icmp error packets. 1039 // 1040 if (RxData != NULL) { 1041 goto CleanUp; 1042 } else { 1043 goto Resume; 1044 } 1045 } 1046 1047 // 1048 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP). 1049 // 1050 ASSERT (RxData != NULL); 1051 if (RxData == NULL) { 1052 goto Resume; 1053 } 1054 1055 if (NULL == IpIo->PktRcvdNotify) { 1056 goto CleanUp; 1057 } 1058 1059 if (IpIo->IpVersion == IP_VERSION_4) { 1060 ASSERT (RxData->Ip4RxData.Header != NULL); 1061 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) { 1062 // 1063 // The source address is a broadcast address, discard it. 1064 // 1065 goto CleanUp; 1066 } 1067 if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) && 1068 (IpIo->SubnetMask != 0) && 1069 IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) && 1070 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) { 1071 // 1072 // The source address doesn't match StationIp and it's not a unicast IP address, discard it. 1073 // 1074 goto CleanUp; 1075 } 1076 1077 if (RxData->Ip4RxData.DataLength == 0) { 1078 // 1079 // Discard zero length data payload packet. 1080 // 1081 goto CleanUp; 1082 } 1083 1084 // 1085 // The fragment should always be valid for non-zero length packet. 1086 // 1087 ASSERT (RxData->Ip4RxData.FragmentCount != 0); 1088 1089 // 1090 // Create a netbuffer representing IPv4 packet 1091 // 1092 Pkt = NetbufFromExt ( 1093 (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable, 1094 RxData->Ip4RxData.FragmentCount, 1095 0, 1096 0, 1097 IpIoExtFree, 1098 RxData->Ip4RxData.RecycleSignal 1099 ); 1100 if (NULL == Pkt) { 1101 goto CleanUp; 1102 } 1103 1104 // 1105 // Create a net session 1106 // 1107 Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress); 1108 Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress); 1109 Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header; 1110 Session.IpHdrLen = RxData->Ip4RxData.HeaderLength; 1111 Session.IpVersion = IP_VERSION_4; 1112 } else { 1113 ASSERT (RxData->Ip6RxData.Header != NULL); 1114 if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) { 1115 goto CleanUp; 1116 } 1117 1118 if (RxData->Ip6RxData.DataLength == 0) { 1119 // 1120 // Discard zero length data payload packet. 1121 // 1122 goto CleanUp; 1123 } 1124 1125 // 1126 // The fragment should always be valid for non-zero length packet. 1127 // 1128 ASSERT (RxData->Ip6RxData.FragmentCount != 0); 1129 1130 // 1131 // Create a netbuffer representing IPv6 packet 1132 // 1133 Pkt = NetbufFromExt ( 1134 (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable, 1135 RxData->Ip6RxData.FragmentCount, 1136 0, 1137 0, 1138 IpIoExtFree, 1139 RxData->Ip6RxData.RecycleSignal 1140 ); 1141 if (NULL == Pkt) { 1142 goto CleanUp; 1143 } 1144 1145 // 1146 // Create a net session 1147 // 1148 CopyMem ( 1149 &Session.Source, 1150 &RxData->Ip6RxData.Header->SourceAddress, 1151 sizeof(EFI_IPv6_ADDRESS) 1152 ); 1153 CopyMem ( 1154 &Session.Dest, 1155 &RxData->Ip6RxData.Header->DestinationAddress, 1156 sizeof(EFI_IPv6_ADDRESS) 1157 ); 1158 Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header; 1159 Session.IpHdrLen = RxData->Ip6RxData.HeaderLength; 1160 Session.IpVersion = IP_VERSION_6; 1161 } 1162 1163 if (EFI_SUCCESS == Status) { 1164 1165 IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext); 1166 } else { 1167 // 1168 // Status is EFI_ICMP_ERROR 1169 // 1170 Status = IpIoIcmpHandler (IpIo, Pkt, &Session); 1171 if (EFI_ERROR (Status)) { 1172 NetbufFree (Pkt); 1173 } 1174 } 1175 1176 goto Resume; 1177 1178 CleanUp: 1179 1180 if (IpIo->IpVersion == IP_VERSION_4){ 1181 gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal); 1182 } else { 1183 gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal); 1184 } 1185 1186 Resume: 1187 1188 if (IpIo->IpVersion == IP_VERSION_4){ 1189 IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token)); 1190 } else { 1191 IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token)); 1192 } 1193 } 1194 1195 /** 1196 This function add IpIoListenHandlerDpc to the end of the DPC queue. 1197 1198 @param[in] Event The event signaled. 1199 @param[in] Context The context passed in by the event notifier. 1200 1201 **/ 1202 VOID 1203 EFIAPI 1204 IpIoListenHandler ( 1205 IN EFI_EVENT Event, 1206 IN VOID *Context 1207 ) 1208 { 1209 // 1210 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK 1211 // 1212 QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context); 1213 } 1214 1215 1216 /** 1217 Create a new IP_IO instance. 1218 1219 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1220 1221 This function uses IP4/IP6 service binding protocol in Controller to create 1222 an IP4/IP6 child (aka IP4/IP6 instance). 1223 1224 @param[in] Image The image handle of the driver or application that 1225 consumes IP_IO. 1226 @param[in] Controller The controller handle that has IP4 or IP6 service 1227 binding protocol installed. 1228 @param[in] IpVersion The version of the IP protocol to use, either 1229 IPv4 or IPv6. 1230 1231 @return Pointer to a newly created IP_IO instance, or NULL if failed. 1232 1233 **/ 1234 IP_IO * 1235 EFIAPI 1236 IpIoCreate ( 1237 IN EFI_HANDLE Image, 1238 IN EFI_HANDLE Controller, 1239 IN UINT8 IpVersion 1240 ) 1241 { 1242 EFI_STATUS Status; 1243 IP_IO *IpIo; 1244 EFI_EVENT Event; 1245 1246 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); 1247 1248 IpIo = AllocateZeroPool (sizeof (IP_IO)); 1249 if (NULL == IpIo) { 1250 return NULL; 1251 } 1252 1253 InitializeListHead (&(IpIo->PendingSndList)); 1254 InitializeListHead (&(IpIo->IpList)); 1255 IpIo->Controller = Controller; 1256 IpIo->Image = Image; 1257 IpIo->IpVersion = IpVersion; 1258 Event = NULL; 1259 1260 Status = gBS->CreateEvent ( 1261 EVT_NOTIFY_SIGNAL, 1262 TPL_NOTIFY, 1263 IpIoListenHandler, 1264 IpIo, 1265 &Event 1266 ); 1267 if (EFI_ERROR (Status)) { 1268 goto ReleaseIpIo; 1269 } 1270 1271 if (IpVersion == IP_VERSION_4) { 1272 IpIo->RcvToken.Ip4Token.Event = Event; 1273 } else { 1274 IpIo->RcvToken.Ip6Token.Event = Event; 1275 } 1276 1277 // 1278 // Create an IP child and open IP protocol 1279 // 1280 Status = IpIoCreateIpChildOpenProtocol ( 1281 Controller, 1282 Image, 1283 &IpIo->ChildHandle, 1284 IpVersion, 1285 (VOID **) & (IpIo->Ip) 1286 ); 1287 if (EFI_ERROR (Status)) { 1288 goto ReleaseIpIo; 1289 } 1290 1291 return IpIo; 1292 1293 ReleaseIpIo: 1294 1295 if (Event != NULL) { 1296 gBS->CloseEvent (Event); 1297 } 1298 1299 gBS->FreePool (IpIo); 1300 1301 return NULL; 1302 } 1303 1304 1305 /** 1306 Open an IP_IO instance for use. 1307 1308 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1309 1310 This function is called after IpIoCreate(). It is used for configuring the IP 1311 instance and register the callbacks and their context data for sending and 1312 receiving IP packets. 1313 1314 @param[in, out] IpIo Pointer to an IP_IO instance that needs 1315 to open. 1316 @param[in] OpenData The configuration data and callbacks for 1317 the IP_IO instance. 1318 1319 @retval EFI_SUCCESS The IP_IO instance opened with OpenData 1320 successfully. 1321 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to 1322 reopen it. 1323 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported. 1324 @retval EFI_INVALID_PARAMETER Invalid input parameter. 1325 @retval Others Error condition occurred. 1326 1327 **/ 1328 EFI_STATUS 1329 EFIAPI 1330 IpIoOpen ( 1331 IN OUT IP_IO *IpIo, 1332 IN IP_IO_OPEN_DATA *OpenData 1333 ) 1334 { 1335 EFI_STATUS Status; 1336 UINT8 IpVersion; 1337 1338 if (IpIo == NULL || OpenData == NULL) { 1339 return EFI_INVALID_PARAMETER; 1340 } 1341 1342 if (IpIo->IsConfigured) { 1343 return EFI_ACCESS_DENIED; 1344 } 1345 1346 IpVersion = IpIo->IpVersion; 1347 1348 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); 1349 1350 // 1351 // configure ip 1352 // 1353 if (IpVersion == IP_VERSION_4){ 1354 // 1355 // RawData mode is no supported. 1356 // 1357 ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData); 1358 if (OpenData->IpConfigData.Ip4CfgData.RawData) { 1359 return EFI_UNSUPPORTED; 1360 } 1361 1362 if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) { 1363 IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress); 1364 IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask); 1365 } 1366 1367 Status = IpIo->Ip.Ip4->Configure ( 1368 IpIo->Ip.Ip4, 1369 &OpenData->IpConfigData.Ip4CfgData 1370 ); 1371 } else { 1372 1373 Status = IpIo->Ip.Ip6->Configure ( 1374 IpIo->Ip.Ip6, 1375 &OpenData->IpConfigData.Ip6CfgData 1376 ); 1377 } 1378 1379 if (EFI_ERROR (Status)) { 1380 return Status; 1381 } 1382 1383 // 1384 // @bug To delete the default route entry in this Ip, if it is: 1385 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified 1386 // @bug its code 1387 // 1388 if (IpVersion == IP_VERSION_4){ 1389 Status = IpIo->Ip.Ip4->Routes ( 1390 IpIo->Ip.Ip4, 1391 TRUE, 1392 &mZeroIp4Addr, 1393 &mZeroIp4Addr, 1394 &mZeroIp4Addr 1395 ); 1396 1397 if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) { 1398 return Status; 1399 } 1400 } 1401 1402 IpIo->PktRcvdNotify = OpenData->PktRcvdNotify; 1403 IpIo->PktSentNotify = OpenData->PktSentNotify; 1404 1405 IpIo->RcvdContext = OpenData->RcvdContext; 1406 IpIo->SndContext = OpenData->SndContext; 1407 1408 if (IpVersion == IP_VERSION_4){ 1409 IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol; 1410 1411 // 1412 // start to listen incoming packet 1413 // 1414 Status = IpIo->Ip.Ip4->Receive ( 1415 IpIo->Ip.Ip4, 1416 &(IpIo->RcvToken.Ip4Token) 1417 ); 1418 if (EFI_ERROR (Status)) { 1419 IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL); 1420 return Status; 1421 } 1422 1423 } else { 1424 1425 IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol; 1426 Status = IpIo->Ip.Ip6->Receive ( 1427 IpIo->Ip.Ip6, 1428 &(IpIo->RcvToken.Ip6Token) 1429 ); 1430 if (EFI_ERROR (Status)) { 1431 IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL); 1432 return Status; 1433 } 1434 } 1435 1436 IpIo->IsConfigured = TRUE; 1437 InsertTailList (&mActiveIpIoList, &IpIo->Entry); 1438 1439 return Status; 1440 } 1441 1442 1443 /** 1444 Stop an IP_IO instance. 1445 1446 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1447 1448 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all 1449 the pending send/receive tokens will be canceled. 1450 1451 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop. 1452 1453 @retval EFI_SUCCESS The IP_IO instance stopped successfully. 1454 @retval EFI_INVALID_PARAMETER Invalid input parameter. 1455 @retval Others Error condition occurred. 1456 1457 **/ 1458 EFI_STATUS 1459 EFIAPI 1460 IpIoStop ( 1461 IN OUT IP_IO *IpIo 1462 ) 1463 { 1464 EFI_STATUS Status; 1465 IP_IO_IP_INFO *IpInfo; 1466 UINT8 IpVersion; 1467 1468 if (IpIo == NULL) { 1469 return EFI_INVALID_PARAMETER; 1470 } 1471 1472 if (!IpIo->IsConfigured) { 1473 return EFI_SUCCESS; 1474 } 1475 1476 IpVersion = IpIo->IpVersion; 1477 1478 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); 1479 1480 // 1481 // Remove the IpIo from the active IpIo list. 1482 // 1483 RemoveEntryList (&IpIo->Entry); 1484 1485 // 1486 // Configure NULL Ip 1487 // 1488 if (IpVersion == IP_VERSION_4) { 1489 Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL); 1490 } else { 1491 Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL); 1492 } 1493 if (EFI_ERROR (Status)) { 1494 return Status; 1495 } 1496 1497 IpIo->IsConfigured = FALSE; 1498 1499 // 1500 // Destroy the Ip List used by IpIo 1501 // 1502 1503 while (!IsListEmpty (&(IpIo->IpList))) { 1504 IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry); 1505 1506 IpIoRemoveIp (IpIo, IpInfo); 1507 } 1508 1509 // 1510 // All pending send tokens should be flushed by resetting the IP instances. 1511 // 1512 ASSERT (IsListEmpty (&IpIo->PendingSndList)); 1513 1514 // 1515 // Close the receive event. 1516 // 1517 if (IpVersion == IP_VERSION_4){ 1518 gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event); 1519 } else { 1520 gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event); 1521 } 1522 1523 return EFI_SUCCESS; 1524 } 1525 1526 1527 /** 1528 Destroy an IP_IO instance. 1529 1530 This function is paired with IpIoCreate(). The IP_IO will be closed first. 1531 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild(). 1532 1533 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be 1534 destroyed. 1535 1536 @retval EFI_SUCCESS The IP_IO instance destroyed successfully. 1537 @retval Others Error condition occurred. 1538 1539 **/ 1540 EFI_STATUS 1541 EFIAPI 1542 IpIoDestroy ( 1543 IN OUT IP_IO *IpIo 1544 ) 1545 { 1546 EFI_STATUS Status; 1547 1548 // 1549 // Stop the IpIo. 1550 // 1551 Status = IpIoStop (IpIo); 1552 if (EFI_ERROR (Status)) { 1553 return Status; 1554 } 1555 1556 // 1557 // Close the IP protocol and destroy the child. 1558 // 1559 Status = IpIoCloseProtocolDestroyIpChild ( 1560 IpIo->Controller, 1561 IpIo->Image, 1562 IpIo->ChildHandle, 1563 IpIo->IpVersion 1564 ); 1565 if (EFI_ERROR (Status)) { 1566 return Status; 1567 } 1568 1569 gBS->FreePool (IpIo); 1570 1571 return EFI_SUCCESS; 1572 } 1573 1574 1575 /** 1576 Send out an IP packet. 1577 1578 This function is called after IpIoOpen(). The data to be sent is wrapped in 1579 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be 1580 overridden by Sender. Other sending configs, like source address and gateway 1581 address etc., are specified in OverrideData. 1582 1583 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP 1584 packet. 1585 @param[in, out] Pkt Pointer to the IP packet to be sent. 1586 @param[in] Sender The IP protocol instance used for sending. 1587 @param[in] Context Optional context data. 1588 @param[in] NotifyData Optional notify data. 1589 @param[in] Dest The destination IP address to send this packet to. 1590 This parameter is optional when using IPv6. 1591 @param[in] OverrideData The data to override some configuration of the IP 1592 instance used for sending. 1593 1594 @retval EFI_SUCCESS The operation is completed successfully. 1595 @retval EFI_INVALID_PARAMETER The input parameter is not correct. 1596 @retval EFI_NOT_STARTED The IpIo is not configured. 1597 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit. 1598 @retval Others Error condition occurred. 1599 1600 **/ 1601 EFI_STATUS 1602 EFIAPI 1603 IpIoSend ( 1604 IN OUT IP_IO *IpIo, 1605 IN OUT NET_BUF *Pkt, 1606 IN IP_IO_IP_INFO *Sender OPTIONAL, 1607 IN VOID *Context OPTIONAL, 1608 IN VOID *NotifyData OPTIONAL, 1609 IN EFI_IP_ADDRESS *Dest OPTIONAL, 1610 IN IP_IO_OVERRIDE *OverrideData OPTIONAL 1611 ) 1612 { 1613 EFI_STATUS Status; 1614 IP_IO_IP_PROTOCOL Ip; 1615 IP_IO_SEND_ENTRY *SndEntry; 1616 1617 if ((IpIo == NULL) || (Pkt == NULL)) { 1618 return EFI_INVALID_PARAMETER; 1619 } 1620 1621 if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) { 1622 return EFI_INVALID_PARAMETER; 1623 } 1624 1625 if (!IpIo->IsConfigured) { 1626 return EFI_NOT_STARTED; 1627 } 1628 1629 Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip; 1630 1631 // 1632 // create a new SndEntry 1633 // 1634 SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData); 1635 if (NULL == SndEntry) { 1636 return EFI_OUT_OF_RESOURCES; 1637 } 1638 1639 // 1640 // Send this Packet 1641 // 1642 if (IpIo->IpVersion == IP_VERSION_4){ 1643 Status = Ip.Ip4->Transmit ( 1644 Ip.Ip4, 1645 &SndEntry->SndToken.Ip4Token 1646 ); 1647 } else { 1648 Status = Ip.Ip6->Transmit ( 1649 Ip.Ip6, 1650 &SndEntry->SndToken.Ip6Token 1651 ); 1652 } 1653 1654 if (EFI_ERROR (Status)) { 1655 IpIoDestroySndEntry (SndEntry); 1656 } 1657 1658 return Status; 1659 } 1660 1661 1662 /** 1663 Cancel the IP transmit token which wraps this Packet. 1664 1665 If IpIo is NULL, then ASSERT(). 1666 If Packet is NULL, then ASSERT(). 1667 1668 @param[in] IpIo Pointer to the IP_IO instance. 1669 @param[in] Packet Pointer to the packet of NET_BUF to cancel. 1670 1671 **/ 1672 VOID 1673 EFIAPI 1674 IpIoCancelTxToken ( 1675 IN IP_IO *IpIo, 1676 IN VOID *Packet 1677 ) 1678 { 1679 LIST_ENTRY *Node; 1680 IP_IO_SEND_ENTRY *SndEntry; 1681 IP_IO_IP_PROTOCOL Ip; 1682 1683 ASSERT ((IpIo != NULL) && (Packet != NULL)); 1684 1685 NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) { 1686 1687 SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry); 1688 1689 if (SndEntry->Pkt == Packet) { 1690 1691 Ip = SndEntry->Ip; 1692 1693 if (IpIo->IpVersion == IP_VERSION_4) { 1694 Ip.Ip4->Cancel ( 1695 Ip.Ip4, 1696 &SndEntry->SndToken.Ip4Token 1697 ); 1698 } else { 1699 Ip.Ip6->Cancel ( 1700 Ip.Ip6, 1701 &SndEntry->SndToken.Ip6Token 1702 ); 1703 } 1704 1705 break; 1706 } 1707 } 1708 1709 } 1710 1711 1712 /** 1713 Add a new IP instance for sending data. 1714 1715 If IpIo is NULL, then ASSERT(). 1716 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1717 1718 The function is used to add the IP_IO to the IP_IO sending list. The caller 1719 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send 1720 data. 1721 1722 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP 1723 instance for sending purpose. 1724 1725 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed. 1726 1727 **/ 1728 IP_IO_IP_INFO * 1729 EFIAPI 1730 IpIoAddIp ( 1731 IN OUT IP_IO *IpIo 1732 ) 1733 { 1734 EFI_STATUS Status; 1735 IP_IO_IP_INFO *IpInfo; 1736 EFI_EVENT Event; 1737 1738 ASSERT (IpIo != NULL); 1739 ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6)); 1740 1741 IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO)); 1742 if (IpInfo == NULL) { 1743 return NULL; 1744 } 1745 1746 // 1747 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP 1748 // instance. 1749 // 1750 InitializeListHead (&IpInfo->Entry); 1751 IpInfo->ChildHandle = NULL; 1752 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr)); 1753 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask)); 1754 1755 IpInfo->RefCnt = 1; 1756 IpInfo->IpVersion = IpIo->IpVersion; 1757 1758 // 1759 // Create the IP instance and open the IP protocol. 1760 // 1761 Status = IpIoCreateIpChildOpenProtocol ( 1762 IpIo->Controller, 1763 IpIo->Image, 1764 &IpInfo->ChildHandle, 1765 IpInfo->IpVersion, 1766 (VOID **) &IpInfo->Ip 1767 ); 1768 if (EFI_ERROR (Status)) { 1769 goto ReleaseIpInfo; 1770 } 1771 1772 // 1773 // Create the event for the DummyRcvToken. 1774 // 1775 Status = gBS->CreateEvent ( 1776 EVT_NOTIFY_SIGNAL, 1777 TPL_NOTIFY, 1778 IpIoDummyHandler, 1779 IpInfo, 1780 &Event 1781 ); 1782 if (EFI_ERROR (Status)) { 1783 goto ReleaseIpChild; 1784 } 1785 1786 if (IpInfo->IpVersion == IP_VERSION_4) { 1787 IpInfo->DummyRcvToken.Ip4Token.Event = Event; 1788 } else { 1789 IpInfo->DummyRcvToken.Ip6Token.Event = Event; 1790 } 1791 1792 // 1793 // Link this IpInfo into the IpIo. 1794 // 1795 InsertTailList (&IpIo->IpList, &IpInfo->Entry); 1796 1797 return IpInfo; 1798 1799 ReleaseIpChild: 1800 1801 IpIoCloseProtocolDestroyIpChild ( 1802 IpIo->Controller, 1803 IpIo->Image, 1804 IpInfo->ChildHandle, 1805 IpInfo->IpVersion 1806 ); 1807 1808 ReleaseIpInfo: 1809 1810 gBS->FreePool (IpInfo); 1811 1812 return NULL; 1813 } 1814 1815 1816 /** 1817 Configure the IP instance of this IpInfo and start the receiving if IpConfigData 1818 is not NULL. 1819 1820 If IpInfo is NULL, then ASSERT(). 1821 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1822 1823 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance. 1824 @param[in, out] IpConfigData The IP configure data used to configure the IP 1825 instance, if NULL the IP instance is reset. If 1826 UseDefaultAddress is set to TRUE, and the configure 1827 operation succeeds, the default address information 1828 is written back in this IpConfigData. 1829 1830 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully 1831 or no need to reconfigure it. 1832 @retval Others Configuration fails. 1833 1834 **/ 1835 EFI_STATUS 1836 EFIAPI 1837 IpIoConfigIp ( 1838 IN OUT IP_IO_IP_INFO *IpInfo, 1839 IN OUT VOID *IpConfigData OPTIONAL 1840 ) 1841 { 1842 EFI_STATUS Status; 1843 IP_IO_IP_PROTOCOL Ip; 1844 UINT8 IpVersion; 1845 EFI_IP4_MODE_DATA Ip4ModeData; 1846 EFI_IP6_MODE_DATA Ip6ModeData; 1847 1848 ASSERT (IpInfo != NULL); 1849 1850 if (IpInfo->RefCnt > 1) { 1851 // 1852 // This IP instance is shared, don't reconfigure it until it has only one 1853 // consumer. Currently, only the tcp children cloned from their passive parent 1854 // will share the same IP. So this cases only happens while IpConfigData is NULL, 1855 // let the last consumer clean the IP instance. 1856 // 1857 return EFI_SUCCESS; 1858 } 1859 1860 IpVersion = IpInfo->IpVersion; 1861 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); 1862 1863 Ip = IpInfo->Ip; 1864 1865 if (IpInfo->IpVersion == IP_VERSION_4) { 1866 Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData); 1867 } else { 1868 Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData); 1869 } 1870 1871 if (EFI_ERROR (Status)) { 1872 return Status; 1873 } 1874 1875 if (IpConfigData != NULL) { 1876 if (IpInfo->IpVersion == IP_VERSION_4) { 1877 1878 if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) { 1879 Status = Ip.Ip4->GetModeData ( 1880 Ip.Ip4, 1881 &Ip4ModeData, 1882 NULL, 1883 NULL 1884 ); 1885 if (EFI_ERROR (Status)) { 1886 Ip.Ip4->Configure (Ip.Ip4, NULL); 1887 return Status; 1888 } 1889 1890 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress); 1891 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask); 1892 } 1893 1894 CopyMem ( 1895 &IpInfo->Addr.Addr, 1896 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress, 1897 sizeof (IP4_ADDR) 1898 ); 1899 CopyMem ( 1900 &IpInfo->PreMask.SubnetMask, 1901 &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask, 1902 sizeof (IP4_ADDR) 1903 ); 1904 1905 Status = Ip.Ip4->Receive ( 1906 Ip.Ip4, 1907 &IpInfo->DummyRcvToken.Ip4Token 1908 ); 1909 if (EFI_ERROR (Status)) { 1910 Ip.Ip4->Configure (Ip.Ip4, NULL); 1911 } 1912 } else { 1913 Status = Ip.Ip6->GetModeData ( 1914 Ip.Ip6, 1915 &Ip6ModeData, 1916 NULL, 1917 NULL 1918 ); 1919 if (EFI_ERROR (Status)) { 1920 Ip.Ip6->Configure (Ip.Ip6, NULL); 1921 return Status; 1922 } 1923 1924 if (Ip6ModeData.IsConfigured) { 1925 CopyMem ( 1926 &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress, 1927 &Ip6ModeData.ConfigData.StationAddress, 1928 sizeof (EFI_IPv6_ADDRESS) 1929 ); 1930 1931 if (Ip6ModeData.AddressList != NULL) { 1932 FreePool (Ip6ModeData.AddressList); 1933 } 1934 1935 if (Ip6ModeData.GroupTable != NULL) { 1936 FreePool (Ip6ModeData.GroupTable); 1937 } 1938 1939 if (Ip6ModeData.RouteTable != NULL) { 1940 FreePool (Ip6ModeData.RouteTable); 1941 } 1942 1943 if (Ip6ModeData.NeighborCache != NULL) { 1944 FreePool (Ip6ModeData.NeighborCache); 1945 } 1946 1947 if (Ip6ModeData.PrefixTable != NULL) { 1948 FreePool (Ip6ModeData.PrefixTable); 1949 } 1950 1951 if (Ip6ModeData.IcmpTypeList != NULL) { 1952 FreePool (Ip6ModeData.IcmpTypeList); 1953 } 1954 1955 } else { 1956 Status = EFI_NO_MAPPING; 1957 return Status; 1958 } 1959 1960 CopyMem ( 1961 &IpInfo->Addr, 1962 &Ip6ModeData.ConfigData.StationAddress, 1963 sizeof (EFI_IPv6_ADDRESS) 1964 ); 1965 1966 Status = Ip.Ip6->Receive ( 1967 Ip.Ip6, 1968 &IpInfo->DummyRcvToken.Ip6Token 1969 ); 1970 if (EFI_ERROR (Status)) { 1971 Ip.Ip6->Configure (Ip.Ip6, NULL); 1972 } 1973 } 1974 } else { 1975 // 1976 // The IP instance is reset, set the stored Addr and SubnetMask to zero. 1977 // 1978 ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr)); 1979 ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask)); 1980 } 1981 1982 return Status; 1983 } 1984 1985 1986 /** 1987 Destroy an IP instance maintained in IpIo->IpList for 1988 sending purpose. 1989 1990 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT(). 1991 1992 This function pairs with IpIoAddIp(). The IpInfo is previously created by 1993 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance 1994 will be destroyed if the RefCnt is zero. 1995 1996 @param[in] IpIo Pointer to the IP_IO instance. 1997 @param[in] IpInfo Pointer to the IpInfo to be removed. 1998 1999 **/ 2000 VOID 2001 EFIAPI 2002 IpIoRemoveIp ( 2003 IN IP_IO *IpIo, 2004 IN IP_IO_IP_INFO *IpInfo 2005 ) 2006 { 2007 2008 UINT8 IpVersion; 2009 2010 if (IpIo == NULL || IpInfo == NULL) { 2011 return; 2012 } 2013 2014 ASSERT (IpInfo->RefCnt > 0); 2015 2016 NET_PUT_REF (IpInfo); 2017 2018 if (IpInfo->RefCnt > 0) { 2019 2020 return; 2021 } 2022 2023 IpVersion = IpIo->IpVersion; 2024 2025 ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); 2026 2027 RemoveEntryList (&IpInfo->Entry); 2028 2029 if (IpVersion == IP_VERSION_4){ 2030 IpInfo->Ip.Ip4->Configure ( 2031 IpInfo->Ip.Ip4, 2032 NULL 2033 ); 2034 IpIoCloseProtocolDestroyIpChild ( 2035 IpIo->Controller, 2036 IpIo->Image, 2037 IpInfo->ChildHandle, 2038 IP_VERSION_4 2039 ); 2040 2041 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event); 2042 2043 } else { 2044 2045 IpInfo->Ip.Ip6->Configure ( 2046 IpInfo->Ip.Ip6, 2047 NULL 2048 ); 2049 2050 IpIoCloseProtocolDestroyIpChild ( 2051 IpIo->Controller, 2052 IpIo->Image, 2053 IpInfo->ChildHandle, 2054 IP_VERSION_6 2055 ); 2056 2057 gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event); 2058 } 2059 2060 FreePool (IpInfo); 2061 } 2062 2063 2064 /** 2065 Find the first IP protocol maintained in IpIo whose local 2066 address is the same as Src. 2067 2068 This function is called when the caller needs the IpIo to send data to the 2069 specified Src. The IpIo was added previously by IpIoAddIp(). 2070 2071 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance. 2072 @param[in] IpVersion The version of the IP protocol to use, either 2073 IPv4 or IPv6. 2074 @param[in] Src The local IP address. 2075 2076 @return Pointer to the IP protocol can be used for sending purpose and its local 2077 address is the same with Src. NULL if failed. 2078 2079 **/ 2080 IP_IO_IP_INFO * 2081 EFIAPI 2082 IpIoFindSender ( 2083 IN OUT IP_IO **IpIo, 2084 IN UINT8 IpVersion, 2085 IN EFI_IP_ADDRESS *Src 2086 ) 2087 { 2088 LIST_ENTRY *IpIoEntry; 2089 IP_IO *IpIoPtr; 2090 LIST_ENTRY *IpInfoEntry; 2091 IP_IO_IP_INFO *IpInfo; 2092 2093 if (IpIo == NULL || Src == NULL) { 2094 return NULL; 2095 } 2096 2097 if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) { 2098 return NULL; 2099 } 2100 2101 NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) { 2102 IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry); 2103 2104 if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) { 2105 continue; 2106 } 2107 2108 NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) { 2109 IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry); 2110 if (IpInfo->IpVersion == IP_VERSION_4){ 2111 2112 if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) { 2113 *IpIo = IpIoPtr; 2114 return IpInfo; 2115 } 2116 2117 } else { 2118 2119 if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) { 2120 *IpIo = IpIoPtr; 2121 return IpInfo; 2122 } 2123 } 2124 } 2125 } 2126 2127 // 2128 // No match. 2129 // 2130 return NULL; 2131 } 2132 2133 2134 /** 2135 Get the ICMP error map information. 2136 2137 The ErrorStatus will be returned. The IsHard and Notify are optional. If they 2138 are not NULL, this routine will fill them. 2139 2140 @param[in] IcmpError IcmpError Type. 2141 @param[in] IpVersion The version of the IP protocol to use, 2142 either IPv4 or IPv6. 2143 @param[out] IsHard If TRUE, indicates that it is a hard error. 2144 @param[out] Notify If TRUE, SockError needs to be notified. 2145 2146 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code. 2147 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE. 2148 2149 **/ 2150 EFI_STATUS 2151 EFIAPI 2152 IpIoGetIcmpErrStatus ( 2153 IN UINT8 IcmpError, 2154 IN UINT8 IpVersion, 2155 OUT BOOLEAN *IsHard OPTIONAL, 2156 OUT BOOLEAN *Notify OPTIONAL 2157 ) 2158 { 2159 if (IpVersion == IP_VERSION_4 ) { 2160 ASSERT (IcmpError <= ICMP_ERR_PARAMPROB); 2161 2162 if (IsHard != NULL) { 2163 *IsHard = mIcmpErrMap[IcmpError].IsHard; 2164 } 2165 2166 if (Notify != NULL) { 2167 *Notify = mIcmpErrMap[IcmpError].Notify; 2168 } 2169 2170 switch (IcmpError) { 2171 case ICMP_ERR_UNREACH_NET: 2172 return EFI_NETWORK_UNREACHABLE; 2173 2174 case ICMP_ERR_TIMXCEED_INTRANS: 2175 case ICMP_ERR_TIMXCEED_REASS: 2176 case ICMP_ERR_UNREACH_HOST: 2177 return EFI_HOST_UNREACHABLE; 2178 2179 case ICMP_ERR_UNREACH_PROTOCOL: 2180 return EFI_PROTOCOL_UNREACHABLE; 2181 2182 case ICMP_ERR_UNREACH_PORT: 2183 return EFI_PORT_UNREACHABLE; 2184 2185 case ICMP_ERR_MSGSIZE: 2186 case ICMP_ERR_UNREACH_SRCFAIL: 2187 case ICMP_ERR_QUENCH: 2188 case ICMP_ERR_PARAMPROB: 2189 return EFI_ICMP_ERROR; 2190 2191 default: 2192 ASSERT (FALSE); 2193 return EFI_UNSUPPORTED; 2194 } 2195 2196 } else if (IpVersion == IP_VERSION_6) { 2197 2198 ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION); 2199 2200 if (IsHard != NULL) { 2201 *IsHard = mIcmp6ErrMap[IcmpError].IsHard; 2202 } 2203 2204 if (Notify != NULL) { 2205 *Notify = mIcmp6ErrMap[IcmpError].Notify; 2206 } 2207 2208 switch (IcmpError) { 2209 case ICMP6_ERR_UNREACH_NET: 2210 return EFI_NETWORK_UNREACHABLE; 2211 2212 case ICMP6_ERR_UNREACH_HOST: 2213 case ICMP6_ERR_TIMXCEED_HOPLIMIT: 2214 case ICMP6_ERR_TIMXCEED_REASS: 2215 return EFI_HOST_UNREACHABLE; 2216 2217 case ICMP6_ERR_UNREACH_PROTOCOL: 2218 return EFI_PROTOCOL_UNREACHABLE; 2219 2220 case ICMP6_ERR_UNREACH_PORT: 2221 return EFI_PORT_UNREACHABLE; 2222 2223 case ICMP6_ERR_PACKAGE_TOOBIG: 2224 case ICMP6_ERR_PARAMPROB_HEADER: 2225 case ICMP6_ERR_PARAMPROB_NEXHEADER: 2226 case ICMP6_ERR_PARAMPROB_IPV6OPTION: 2227 return EFI_ICMP_ERROR; 2228 2229 default: 2230 ASSERT (FALSE); 2231 return EFI_UNSUPPORTED; 2232 } 2233 2234 } else { 2235 // 2236 // Should never be here 2237 // 2238 ASSERT (FALSE); 2239 return EFI_UNSUPPORTED; 2240 } 2241 } 2242 2243 2244 /** 2245 Refresh the remote peer's Neighbor Cache entries. 2246 2247 This function is called when the caller needs the IpIo to refresh the existing 2248 IPv6 neighbor cache entries since the neighbor is considered reachable by the 2249 node has recently received a confirmation that packets sent recently to the 2250 neighbor were received by its IP layer. 2251 2252 @param[in] IpIo Pointer to an IP_IO instance 2253 @param[in] Neighbor The IP address of the neighbor 2254 @param[in] Timeout Time in 100-ns units that this entry will 2255 remain in the neighbor cache. A value of 2256 zero means that the entry is permanent. 2257 A value of non-zero means that the entry is 2258 dynamic and will be deleted after Timeout. 2259 2260 @retval EFI_SUCCESS The operation is completed successfully. 2261 @retval EFI_NOT_STARTED The IpIo is not configured. 2262 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid. 2263 @retval EFI_NOT_FOUND The neighbor cache entry is not in the 2264 neighbor table. 2265 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh. 2266 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit. 2267 2268 **/ 2269 EFI_STATUS 2270 EFIAPI 2271 IpIoRefreshNeighbor ( 2272 IN IP_IO *IpIo, 2273 IN EFI_IP_ADDRESS *Neighbor, 2274 IN UINT32 Timeout 2275 ) 2276 { 2277 EFI_IP6_PROTOCOL *Ip; 2278 2279 if (!IpIo->IsConfigured) { 2280 return EFI_NOT_STARTED; 2281 } 2282 2283 if (IpIo->IpVersion != IP_VERSION_6) { 2284 return EFI_UNSUPPORTED; 2285 } 2286 2287 Ip = IpIo->Ip.Ip6; 2288 2289 return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE); 2290 } 2291 2292