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