1 /** @file 2 Support functions implementation for UefiPxeBc Driver. 3 4 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> 5 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 16 #include "PxeBcImpl.h" 17 18 19 /** 20 Flush the previous configration using the new station Ip address. 21 22 @param[in] Private The pointer to the PxeBc private data. 23 @param[in] StationIp The pointer to the station Ip address. 24 @param[in] SubnetMask The pointer to the subnet mask address for v4. 25 26 @retval EFI_SUCCESS Successfully flushed the previous configuration. 27 @retval Others Failed to flush using the new station Ip. 28 29 **/ 30 EFI_STATUS 31 PxeBcFlushStationIp ( 32 PXEBC_PRIVATE_DATA *Private, 33 EFI_IP_ADDRESS *StationIp, 34 EFI_IP_ADDRESS *SubnetMask OPTIONAL 35 ) 36 { 37 EFI_PXE_BASE_CODE_MODE *Mode; 38 EFI_STATUS Status; 39 40 ASSERT (StationIp != NULL); 41 42 Mode = Private->PxeBc.Mode; 43 Status = EFI_SUCCESS; 44 45 if (Mode->UsingIpv6) { 46 47 CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS)); 48 CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS)); 49 50 // 51 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address. 52 // 53 Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token); 54 Private->Ip6->Configure (Private->Ip6, NULL); 55 56 Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData); 57 if (EFI_ERROR (Status)) { 58 goto ON_EXIT; 59 } 60 61 Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token); 62 } else { 63 ASSERT (SubnetMask != NULL); 64 CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS)); 65 CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 66 CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS)); 67 CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 68 69 // 70 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address. 71 // 72 Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken); 73 Private->Ip4->Configure (Private->Ip4, NULL); 74 75 Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData); 76 if (EFI_ERROR (Status)) { 77 goto ON_EXIT; 78 } 79 80 Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken); 81 } 82 83 ON_EXIT: 84 return Status; 85 } 86 87 88 /** 89 Notify the callback function when an event is triggered. 90 91 @param[in] Event The triggered event. 92 @param[in] Context The opaque parameter to the function. 93 94 **/ 95 VOID 96 EFIAPI 97 PxeBcCommonNotify ( 98 IN EFI_EVENT Event, 99 IN VOID *Context 100 ) 101 { 102 *((BOOLEAN *) Context) = TRUE; 103 } 104 105 106 /** 107 Do arp resolution from arp cache in PxeBcMode. 108 109 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE. 110 @param Ip4Addr The Ip4 address for resolution. 111 @param MacAddress The resoluted MAC address if the resolution is successful. 112 The value is undefined if the resolution fails. 113 114 @retval TRUE Found an matched entry. 115 @retval FALSE Did not find a matched entry. 116 117 **/ 118 BOOLEAN 119 PxeBcCheckArpCache ( 120 IN EFI_PXE_BASE_CODE_MODE *Mode, 121 IN EFI_IPv4_ADDRESS *Ip4Addr, 122 OUT EFI_MAC_ADDRESS *MacAddress 123 ) 124 { 125 UINT32 Index; 126 127 ASSERT (!Mode->UsingIpv6); 128 129 // 130 // Check whether the current Arp cache in mode data contains this information or not. 131 // 132 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) { 133 if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) { 134 CopyMem ( 135 MacAddress, 136 &Mode->ArpCache[Index].MacAddr, 137 sizeof (EFI_MAC_ADDRESS) 138 ); 139 return TRUE; 140 } 141 } 142 143 return FALSE; 144 } 145 146 147 /** 148 Update the arp cache periodically. 149 150 @param Event The pointer to EFI_PXE_BC_PROTOCOL. 151 @param Context Context of the timer event. 152 153 **/ 154 VOID 155 EFIAPI 156 PxeBcArpCacheUpdate ( 157 IN EFI_EVENT Event, 158 IN VOID *Context 159 ) 160 { 161 PXEBC_PRIVATE_DATA *Private; 162 EFI_PXE_BASE_CODE_MODE *Mode; 163 EFI_ARP_FIND_DATA *ArpEntry; 164 UINT32 EntryLength; 165 UINT32 EntryCount; 166 UINT32 Index; 167 EFI_STATUS Status; 168 169 Private = (PXEBC_PRIVATE_DATA *) Context; 170 Mode = Private->PxeBc.Mode; 171 172 ASSERT (!Mode->UsingIpv6); 173 174 // 175 // Get the current Arp cache from Arp driver. 176 // 177 Status = Private->Arp->Find ( 178 Private->Arp, 179 TRUE, 180 NULL, 181 &EntryLength, 182 &EntryCount, 183 &ArpEntry, 184 TRUE 185 ); 186 if (EFI_ERROR (Status)) { 187 return; 188 } 189 190 // 191 // Update the Arp cache in mode data. 192 // 193 Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES); 194 195 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) { 196 CopyMem ( 197 &Mode->ArpCache[Index].IpAddr, 198 ArpEntry + 1, 199 ArpEntry->SwAddressLength 200 ); 201 CopyMem ( 202 &Mode->ArpCache[Index].MacAddr, 203 (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength, 204 ArpEntry->HwAddressLength 205 ); 206 ArpEntry = (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength); 207 } 208 } 209 210 211 /** 212 Notify function to handle the received ICMP message in DPC. 213 214 @param Context The PXEBC private data. 215 216 **/ 217 VOID 218 EFIAPI 219 PxeBcIcmpErrorDpcHandle ( 220 IN VOID *Context 221 ) 222 { 223 EFI_STATUS Status; 224 EFI_IP4_RECEIVE_DATA *RxData; 225 EFI_IP4_PROTOCOL *Ip4; 226 PXEBC_PRIVATE_DATA *Private; 227 EFI_PXE_BASE_CODE_MODE *Mode; 228 UINT8 Type; 229 UINTN Index; 230 UINT32 CopiedLen; 231 UINT8 *IcmpError; 232 233 Private = (PXEBC_PRIVATE_DATA *) Context; 234 Mode = &Private->Mode; 235 Status = Private->IcmpToken.Status; 236 RxData = Private->IcmpToken.Packet.RxData; 237 Ip4 = Private->Ip4; 238 239 ASSERT (!Mode->UsingIpv6); 240 241 if (Status == EFI_ABORTED) { 242 // 243 // It's triggered by user cancellation. 244 // 245 return; 246 } 247 248 if (RxData == NULL) { 249 goto ON_EXIT; 250 } 251 252 if (Status != EFI_ICMP_ERROR) { 253 // 254 // The return status should be recognized as EFI_ICMP_ERROR. 255 // 256 gBS->SignalEvent (RxData->RecycleSignal); 257 goto ON_EXIT; 258 } 259 260 if (EFI_IP4 (RxData->Header->SourceAddress) != 0 && 261 !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) { 262 // 263 // The source address of the received packet should be a valid unicast address. 264 // 265 gBS->SignalEvent (RxData->RecycleSignal); 266 goto ON_EXIT; 267 } 268 269 if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) { 270 // 271 // The destination address of the received packet should be equal to the host address. 272 // 273 gBS->SignalEvent (RxData->RecycleSignal); 274 goto ON_EXIT; 275 } 276 277 if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) { 278 // 279 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP. 280 // 281 gBS->SignalEvent (RxData->RecycleSignal); 282 goto ON_EXIT; 283 } 284 285 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer); 286 287 if (Type != ICMP_DEST_UNREACHABLE && 288 Type != ICMP_SOURCE_QUENCH && 289 Type != ICMP_REDIRECT && 290 Type != ICMP_TIME_EXCEEDED && 291 Type != ICMP_PARAMETER_PROBLEM) { 292 // 293 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE. 294 // 295 gBS->SignalEvent (RxData->RecycleSignal); 296 goto ON_EXIT; 297 } 298 299 // 300 // Copy the right ICMP error message into mode data. 301 // 302 CopiedLen = 0; 303 IcmpError = (UINT8 *) &Mode->IcmpError; 304 305 for (Index = 0; Index < RxData->FragmentCount; Index++) { 306 CopiedLen += RxData->FragmentTable[Index].FragmentLength; 307 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) { 308 CopyMem ( 309 IcmpError, 310 RxData->FragmentTable[Index].FragmentBuffer, 311 RxData->FragmentTable[Index].FragmentLength 312 ); 313 } else { 314 CopyMem ( 315 IcmpError, 316 RxData->FragmentTable[Index].FragmentBuffer, 317 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR) 318 ); 319 } 320 IcmpError += CopiedLen; 321 } 322 323 ON_EXIT: 324 Private->IcmpToken.Status = EFI_NOT_READY; 325 Ip4->Receive (Ip4, &Private->IcmpToken); 326 } 327 328 329 /** 330 Callback function to update the latest ICMP6 error message. 331 332 @param Event The event signalled. 333 @param Context The context passed in using the event notifier. 334 335 **/ 336 VOID 337 EFIAPI 338 PxeBcIcmpErrorUpdate ( 339 IN EFI_EVENT Event, 340 IN VOID *Context 341 ) 342 { 343 QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context); 344 } 345 346 347 /** 348 Notify function to handle the received ICMP6 message in DPC. 349 350 @param Context The PXEBC private data. 351 352 **/ 353 VOID 354 EFIAPI 355 PxeBcIcmp6ErrorDpcHandle ( 356 IN VOID *Context 357 ) 358 { 359 PXEBC_PRIVATE_DATA *Private; 360 EFI_IP6_RECEIVE_DATA *RxData; 361 EFI_IP6_PROTOCOL *Ip6; 362 EFI_PXE_BASE_CODE_MODE *Mode; 363 EFI_STATUS Status; 364 UINTN Index; 365 UINT8 Type; 366 UINT32 CopiedLen; 367 UINT8 *Icmp6Error; 368 369 Private = (PXEBC_PRIVATE_DATA *) Context; 370 Mode = &Private->Mode; 371 Status = Private->Icmp6Token.Status; 372 RxData = Private->Icmp6Token.Packet.RxData; 373 Ip6 = Private->Ip6; 374 375 ASSERT (Mode->UsingIpv6); 376 377 if (Status == EFI_ABORTED) { 378 // 379 // It's triggered by user cancellation. 380 // 381 return; 382 } 383 384 if (RxData == NULL) { 385 goto ON_EXIT; 386 } 387 388 if (Status != EFI_ICMP_ERROR) { 389 // 390 // The return status should be recognized as EFI_ICMP_ERROR. 391 // 392 gBS->SignalEvent (RxData->RecycleSignal); 393 goto ON_EXIT; 394 } 395 396 if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) { 397 // 398 // The source address of the received packet should be a valid unicast address. 399 // 400 gBS->SignalEvent (RxData->RecycleSignal); 401 goto ON_EXIT; 402 } 403 404 if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) && 405 !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) { 406 // 407 // The destination address of the received packet should be equal to the host address. 408 // 409 gBS->SignalEvent (RxData->RecycleSignal); 410 goto ON_EXIT; 411 } 412 413 if (RxData->Header->NextHeader != IP6_ICMP) { 414 // 415 // The nextheader in the header of the receveid packet should be IP6_ICMP. 416 // 417 gBS->SignalEvent (RxData->RecycleSignal); 418 goto ON_EXIT; 419 } 420 421 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer); 422 423 if (Type != ICMP_V6_DEST_UNREACHABLE && 424 Type != ICMP_V6_PACKET_TOO_BIG && 425 Type != ICMP_V6_PACKET_TOO_BIG && 426 Type != ICMP_V6_PARAMETER_PROBLEM) { 427 // 428 // The type of the receveid packet should be an ICMP6 error message. 429 // 430 gBS->SignalEvent (RxData->RecycleSignal); 431 goto ON_EXIT; 432 } 433 434 // 435 // Copy the right ICMP6 error message into mode data. 436 // 437 CopiedLen = 0; 438 Icmp6Error = (UINT8 *) &Mode->IcmpError; 439 440 for (Index = 0; Index < RxData->FragmentCount; Index++) { 441 CopiedLen += RxData->FragmentTable[Index].FragmentLength; 442 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) { 443 CopyMem ( 444 Icmp6Error, 445 RxData->FragmentTable[Index].FragmentBuffer, 446 RxData->FragmentTable[Index].FragmentLength 447 ); 448 } else { 449 CopyMem ( 450 Icmp6Error, 451 RxData->FragmentTable[Index].FragmentBuffer, 452 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR) 453 ); 454 } 455 Icmp6Error += CopiedLen; 456 } 457 458 ON_EXIT: 459 Private->Icmp6Token.Status = EFI_NOT_READY; 460 Ip6->Receive (Ip6, &Private->Icmp6Token); 461 } 462 463 464 /** 465 Callback function to update the latest ICMP6 error message. 466 467 @param Event The event signalled. 468 @param Context The context passed in using the event notifier. 469 470 **/ 471 VOID 472 EFIAPI 473 PxeBcIcmp6ErrorUpdate ( 474 IN EFI_EVENT Event, 475 IN VOID *Context 476 ) 477 { 478 QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context); 479 } 480 481 482 /** 483 This function is to configure a UDPv4 instance for UdpWrite. 484 485 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. 486 @param[in] StationIp The pointer to the station address. 487 @param[in] SubnetMask The pointer to the subnet mask. 488 @param[in] Gateway The pointer to the gateway address. 489 @param[in, out] SrcPort The pointer to the source port. 490 @param[in] DoNotFragment If TRUE, fragment is not enabled. 491 Otherwise, fragment is enabled. 492 493 @retval EFI_SUCCESS Successfully configured this instance. 494 @retval Others Failed to configure this instance. 495 496 **/ 497 EFI_STATUS 498 PxeBcConfigUdp4Write ( 499 IN EFI_UDP4_PROTOCOL *Udp4, 500 IN EFI_IPv4_ADDRESS *StationIp, 501 IN EFI_IPv4_ADDRESS *SubnetMask, 502 IN EFI_IPv4_ADDRESS *Gateway, 503 IN OUT UINT16 *SrcPort, 504 IN BOOLEAN DoNotFragment 505 ) 506 { 507 EFI_UDP4_CONFIG_DATA Udp4CfgData; 508 EFI_STATUS Status; 509 510 ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData)); 511 512 Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME; 513 Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME; 514 Udp4CfgData.TypeOfService = DEFAULT_ToS; 515 Udp4CfgData.TimeToLive = DEFAULT_TTL; 516 Udp4CfgData.AllowDuplicatePort = TRUE; 517 Udp4CfgData.DoNotFragment = DoNotFragment; 518 519 CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp)); 520 CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask)); 521 522 Udp4CfgData.StationPort = *SrcPort; 523 524 // 525 // Reset the UDPv4 instance. 526 // 527 Udp4->Configure (Udp4, NULL); 528 529 Status = Udp4->Configure (Udp4, &Udp4CfgData); 530 if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) { 531 // 532 // The basic configuration is OK, need to add the default route entry 533 // 534 Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway); 535 if (EFI_ERROR (Status)) { 536 Udp4->Configure (Udp4, NULL); 537 } 538 } 539 540 if (!EFI_ERROR (Status) && *SrcPort == 0) { 541 Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL); 542 *SrcPort = Udp4CfgData.StationPort; 543 } 544 545 return Status; 546 } 547 548 549 /** 550 This function is to configure a UDPv6 instance for UdpWrite. 551 552 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. 553 @param[in] StationIp The pointer to the station address. 554 @param[in, out] SrcPort The pointer to the source port. 555 556 @retval EFI_SUCCESS Successfully configured this instance. 557 @retval Others Failed to configure this instance. 558 559 **/ 560 EFI_STATUS 561 PxeBcConfigUdp6Write ( 562 IN EFI_UDP6_PROTOCOL *Udp6, 563 IN EFI_IPv6_ADDRESS *StationIp, 564 IN OUT UINT16 *SrcPort 565 ) 566 { 567 EFI_UDP6_CONFIG_DATA CfgData; 568 EFI_STATUS Status; 569 570 ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA)); 571 572 CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME; 573 CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME; 574 CfgData.HopLimit = PXEBC_DEFAULT_HOPLIMIT; 575 CfgData.AllowDuplicatePort = TRUE; 576 CfgData.StationPort = *SrcPort; 577 578 CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS)); 579 580 // 581 // Reset the UDPv6 instance. 582 // 583 Udp6->Configure (Udp6, NULL); 584 585 Status = Udp6->Configure (Udp6, &CfgData); 586 if (EFI_ERROR (Status)) { 587 return Status; 588 } 589 590 if (!EFI_ERROR (Status) && *SrcPort == 0) { 591 Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL); 592 *SrcPort = CfgData.StationPort; 593 } 594 595 return Status; 596 } 597 598 599 /** 600 This function is to configure a UDPv4 instance for UdpWrite. 601 602 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. 603 @param[in] Session The pointer to the UDP4 session data. 604 @param[in] TimeoutEvent The event for timeout. 605 @param[in] Gateway The pointer to the gateway address. 606 @param[in] HeaderSize An optional field which may be set to the length of a header 607 at HeaderPtr to be prefixed to the data at BufferPtr. 608 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be 609 prefixed to the data at BufferPtr. 610 @param[in] BufferSize A pointer to the size of the data at BufferPtr. 611 @param[in] BufferPtr A pointer to the data to be written. 612 613 @retval EFI_SUCCESS Successfully send out data using Udp4Write. 614 @retval Others Failed to send out data. 615 616 **/ 617 EFI_STATUS 618 PxeBcUdp4Write ( 619 IN EFI_UDP4_PROTOCOL *Udp4, 620 IN EFI_UDP4_SESSION_DATA *Session, 621 IN EFI_EVENT TimeoutEvent, 622 IN EFI_IPv4_ADDRESS *Gateway OPTIONAL, 623 IN UINTN *HeaderSize OPTIONAL, 624 IN VOID *HeaderPtr OPTIONAL, 625 IN UINTN *BufferSize, 626 IN VOID *BufferPtr 627 ) 628 { 629 EFI_UDP4_COMPLETION_TOKEN Token; 630 EFI_UDP4_TRANSMIT_DATA *TxData; 631 UINT32 TxLength; 632 UINT32 FragCount; 633 UINT32 DataLength; 634 BOOLEAN IsDone; 635 EFI_STATUS Status; 636 637 // 638 // Arrange one fragment buffer for data, and another fragment buffer for header if has. 639 // 640 FragCount = (HeaderSize != NULL) ? 2 : 1; 641 TxLength = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA); 642 TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength); 643 if (TxData == NULL) { 644 return EFI_OUT_OF_RESOURCES; 645 } 646 647 TxData->FragmentCount = FragCount; 648 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize; 649 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr; 650 DataLength = (UINT32) *BufferSize; 651 652 if (HeaderSize != NULL) { 653 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize; 654 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr; 655 DataLength += (UINT32) *HeaderSize; 656 } 657 658 if (Gateway != NULL) { 659 TxData->GatewayAddress = Gateway; 660 } 661 662 TxData->UdpSessionData = Session; 663 TxData->DataLength = DataLength; 664 Token.Packet.TxData = TxData; 665 Token.Status = EFI_NOT_READY; 666 IsDone = FALSE; 667 668 Status = gBS->CreateEvent ( 669 EVT_NOTIFY_SIGNAL, 670 TPL_NOTIFY, 671 PxeBcCommonNotify, 672 &IsDone, 673 &Token.Event 674 ); 675 if (EFI_ERROR (Status)) { 676 goto ON_EXIT; 677 } 678 679 Status = Udp4->Transmit (Udp4, &Token); 680 if (EFI_ERROR (Status)) { 681 goto ON_EXIT; 682 } 683 684 // 685 // Poll the UDPv6 read instance if no packet received and no timeout triggered. 686 // 687 while (!IsDone && 688 Token.Status == EFI_NOT_READY && 689 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { 690 Udp4->Poll (Udp4); 691 } 692 693 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status; 694 695 ON_EXIT: 696 if (Token.Event != NULL) { 697 gBS->CloseEvent (Token.Event); 698 } 699 FreePool (TxData); 700 701 return Status; 702 } 703 704 705 /** 706 This function is to configure a UDPv4 instance for UdpWrite. 707 708 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. 709 @param[in] Session The pointer to the UDP6 session data. 710 @param[in] TimeoutEvent The event for timeout. 711 @param[in] HeaderSize An optional field which may be set to the length of a header 712 at HeaderPtr to be prefixed to the data at BufferPtr. 713 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be 714 prefixed to the data at BufferPtr. 715 @param[in] BufferSize A pointer to the size of the data at BufferPtr. 716 @param[in] BufferPtr A pointer to the data to be written. 717 718 @retval EFI_SUCCESS Successfully sent out data using Udp6Write. 719 @retval Others Failed to send out data. 720 721 **/ 722 EFI_STATUS 723 PxeBcUdp6Write ( 724 IN EFI_UDP6_PROTOCOL *Udp6, 725 IN EFI_UDP6_SESSION_DATA *Session, 726 IN EFI_EVENT TimeoutEvent, 727 IN UINTN *HeaderSize OPTIONAL, 728 IN VOID *HeaderPtr OPTIONAL, 729 IN UINTN *BufferSize, 730 IN VOID *BufferPtr 731 ) 732 { 733 EFI_UDP6_COMPLETION_TOKEN Token; 734 EFI_UDP6_TRANSMIT_DATA *TxData; 735 UINT32 TxLength; 736 UINT32 FragCount; 737 UINT32 DataLength; 738 BOOLEAN IsDone; 739 EFI_STATUS Status; 740 741 // 742 // Arrange one fragment buffer for data, and another fragment buffer for header if has. 743 // 744 FragCount = (HeaderSize != NULL) ? 2 : 1; 745 TxLength = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA); 746 TxData = (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength); 747 if (TxData == NULL) { 748 return EFI_OUT_OF_RESOURCES; 749 } 750 751 TxData->FragmentCount = FragCount; 752 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize; 753 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr; 754 DataLength = (UINT32) *BufferSize; 755 756 if (HeaderSize != NULL) { 757 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize; 758 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr; 759 DataLength += (UINT32) *HeaderSize; 760 } 761 762 TxData->UdpSessionData = Session; 763 TxData->DataLength = DataLength; 764 Token.Packet.TxData = TxData; 765 Token.Status = EFI_NOT_READY; 766 IsDone = FALSE; 767 768 Status = gBS->CreateEvent ( 769 EVT_NOTIFY_SIGNAL, 770 TPL_NOTIFY, 771 PxeBcCommonNotify, 772 &IsDone, 773 &Token.Event 774 ); 775 if (EFI_ERROR (Status)) { 776 goto ON_EXIT; 777 } 778 779 Status = Udp6->Transmit (Udp6, &Token); 780 if (EFI_ERROR (Status)) { 781 goto ON_EXIT; 782 } 783 784 // 785 // Poll the UDPv6 read instance if no packet received and no timeout triggered. 786 // 787 while (!IsDone && 788 Token.Status == EFI_NOT_READY && 789 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { 790 Udp6->Poll (Udp6); 791 } 792 793 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status; 794 795 ON_EXIT: 796 if (Token.Event != NULL) { 797 gBS->CloseEvent (Token.Event); 798 } 799 FreePool (TxData); 800 801 return Status; 802 } 803 804 805 /** 806 Check the received packet using the Ip filter. 807 808 @param[in] Mode The pointer to the mode data of PxeBc. 809 @param[in] Session The pointer to the current UDPv4 session. 810 @param[in] OpFlags Operation flag for UdpRead/UdpWrite. 811 812 @retval TRUE Passed the Ip filter successfully. 813 @retval FALSE Failed to pass the Ip filter. 814 815 **/ 816 BOOLEAN 817 PxeBcCheckByIpFilter ( 818 IN EFI_PXE_BASE_CODE_MODE *Mode, 819 IN VOID *Session, 820 IN UINT16 OpFlags 821 ) 822 { 823 EFI_IP_ADDRESS DestinationIp; 824 UINTN Index; 825 826 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) { 827 return TRUE; 828 } 829 830 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) { 831 return TRUE; 832 } 833 834 // 835 // Convert the destination address in session data to host order. 836 // 837 if (Mode->UsingIpv6) { 838 CopyMem ( 839 &DestinationIp, 840 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress, 841 sizeof (EFI_IPv6_ADDRESS) 842 ); 843 NTOHLLL (&DestinationIp.v6); 844 } else { 845 ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS)); 846 CopyMem ( 847 &DestinationIp, 848 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress, 849 sizeof (EFI_IPv4_ADDRESS) 850 ); 851 EFI_NTOHL (DestinationIp); 852 } 853 854 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0 && 855 (IP4_IS_MULTICAST (DestinationIp.Addr[0]) || 856 IP6_IS_MULTICAST (&DestinationIp))) { 857 return TRUE; 858 } 859 860 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0 && 861 IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) { 862 ASSERT (!Mode->UsingIpv6); 863 return TRUE; 864 } 865 866 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 && 867 (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) || 868 EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) { 869 // 870 // Matched if the dest address is equal to the station address. 871 // 872 return TRUE; 873 } 874 875 for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) { 876 ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT); 877 if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) || 878 EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) { 879 // 880 // Matched if the dest address is equal to any of address in the filter list. 881 // 882 return TRUE; 883 } 884 } 885 886 return FALSE; 887 } 888 889 890 /** 891 Filter the received packet using the destination Ip. 892 893 @param[in] Mode The pointer to the mode data of PxeBc. 894 @param[in] Session The pointer to the current UDPv4 session. 895 @param[in, out] DestIp The pointer to the destination Ip address. 896 @param[in] OpFlags Operation flag for UdpRead/UdpWrite. 897 898 @retval TRUE Passed the IPv4 filter successfully. 899 @retval FALSE Failed to pass the IPv4 filter. 900 901 **/ 902 BOOLEAN 903 PxeBcCheckByDestIp ( 904 IN EFI_PXE_BASE_CODE_MODE *Mode, 905 IN VOID *Session, 906 IN OUT EFI_IP_ADDRESS *DestIp, 907 IN UINT16 OpFlags 908 ) 909 { 910 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) { 911 // 912 // Copy the destination address from the received packet if accept any. 913 // 914 if (DestIp != NULL) { 915 if (Mode->UsingIpv6) { 916 CopyMem ( 917 DestIp, 918 &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress, 919 sizeof (EFI_IPv6_ADDRESS) 920 ); 921 } else { 922 ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS)); 923 CopyMem ( 924 DestIp, 925 &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress, 926 sizeof (EFI_IPv4_ADDRESS) 927 ); 928 } 929 930 } 931 return TRUE; 932 } else if (DestIp != NULL && 933 (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) || 934 EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))) { 935 // 936 // The destination address in the received packet is matched if present. 937 // 938 return TRUE; 939 } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) || 940 EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)) { 941 // 942 // The destination address in the received packet is equal to the host address. 943 // 944 return TRUE; 945 } 946 947 return FALSE; 948 } 949 950 951 /** 952 Check the received packet using the destination port. 953 954 @param[in] Mode The pointer to the mode data of PxeBc. 955 @param[in] Session The pointer to the current UDPv4 session. 956 @param[in, out] DestPort The pointer to the destination port. 957 @param[in] OpFlags Operation flag for UdpRead/UdpWrite. 958 959 @retval TRUE Passed the IPv4 filter successfully. 960 @retval FALSE Failed to pass the IPv4 filter. 961 962 **/ 963 BOOLEAN 964 PxeBcCheckByDestPort ( 965 IN EFI_PXE_BASE_CODE_MODE *Mode, 966 IN VOID *Session, 967 IN OUT UINT16 *DestPort, 968 IN UINT16 OpFlags 969 ) 970 { 971 UINT16 Port; 972 973 if (Mode->UsingIpv6) { 974 Port = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort; 975 } else { 976 Port = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort; 977 } 978 979 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) { 980 // 981 // Return the destination port in the received packet if accept any. 982 // 983 if (DestPort != NULL) { 984 *DestPort = Port; 985 } 986 return TRUE; 987 } else if (DestPort != NULL && *DestPort == Port) { 988 // 989 // The destination port in the received packet is matched if present. 990 // 991 return TRUE; 992 } 993 994 return FALSE; 995 } 996 997 998 /** 999 Filter the received packet using the source Ip. 1000 1001 @param[in] Mode The pointer to the mode data of PxeBc. 1002 @param[in] Session The pointer to the current UDPv4 session. 1003 @param[in, out] SrcIp The pointer to the source Ip address. 1004 @param[in] OpFlags Operation flag for UdpRead/UdpWrite. 1005 1006 @retval TRUE Passed the IPv4 filter successfully. 1007 @retval FALSE Failed to pass the IPv4 filter. 1008 1009 **/ 1010 BOOLEAN 1011 PxeBcFilterBySrcIp ( 1012 IN EFI_PXE_BASE_CODE_MODE *Mode, 1013 IN VOID *Session, 1014 IN OUT EFI_IP_ADDRESS *SrcIp, 1015 IN UINT16 OpFlags 1016 ) 1017 { 1018 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) { 1019 // 1020 // Copy the source address from the received packet if accept any. 1021 // 1022 if (SrcIp != NULL) { 1023 if (Mode->UsingIpv6) { 1024 CopyMem ( 1025 SrcIp, 1026 &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress, 1027 sizeof (EFI_IPv6_ADDRESS) 1028 ); 1029 } else { 1030 ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS)); 1031 CopyMem ( 1032 SrcIp, 1033 &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress, 1034 sizeof (EFI_IPv4_ADDRESS) 1035 ); 1036 } 1037 1038 } 1039 return TRUE; 1040 } else if (SrcIp != NULL && 1041 (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) || 1042 EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress))) { 1043 // 1044 // The source address in the received packet is matched if present. 1045 // 1046 return TRUE; 1047 } 1048 1049 return FALSE; 1050 } 1051 1052 1053 /** 1054 Filter the received packet using the source port. 1055 1056 @param[in] Mode The pointer to the mode data of PxeBc. 1057 @param[in] Session The pointer to the current UDPv4 session. 1058 @param[in, out] SrcPort The pointer to the source port. 1059 @param[in] OpFlags Operation flag for UdpRead/UdpWrite. 1060 1061 @retval TRUE Passed the IPv4 filter successfully. 1062 @retval FALSE Failed to pass the IPv4 filter. 1063 1064 **/ 1065 BOOLEAN 1066 PxeBcFilterBySrcPort ( 1067 IN EFI_PXE_BASE_CODE_MODE *Mode, 1068 IN VOID *Session, 1069 IN OUT UINT16 *SrcPort, 1070 IN UINT16 OpFlags 1071 ) 1072 { 1073 UINT16 Port; 1074 1075 if (Mode->UsingIpv6) { 1076 Port = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort; 1077 } else { 1078 Port = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort; 1079 } 1080 1081 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) { 1082 // 1083 // Return the source port in the received packet if accept any. 1084 // 1085 if (SrcPort != NULL) { 1086 *SrcPort = Port; 1087 } 1088 return TRUE; 1089 } else if (SrcPort != NULL && *SrcPort == Port) { 1090 // 1091 // The source port in the received packet is matched if present. 1092 // 1093 return TRUE; 1094 } 1095 1096 return FALSE; 1097 } 1098 1099 1100 /** 1101 This function is to receive packet using Udp4Read. 1102 1103 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. 1104 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN. 1105 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE. 1106 @param[in] TimeoutEvent The event for timeout. 1107 @param[in] OpFlags The UDP operation flags. 1108 @param[in] IsDone The pointer to the IsDone flag. 1109 @param[out] IsMatched The pointer to the IsMatched flag. 1110 @param[in, out] DestIp The pointer to the destination address. 1111 @param[in, out] DestPort The pointer to the destination port. 1112 @param[in, out] SrcIp The pointer to the source address. 1113 @param[in, out] SrcPort The pointer to the source port. 1114 1115 @retval EFI_SUCCESS Successfully read the data using Udp4. 1116 @retval Others Failed to send out data. 1117 1118 **/ 1119 EFI_STATUS 1120 PxeBcUdp4Read ( 1121 IN EFI_UDP4_PROTOCOL *Udp4, 1122 IN EFI_UDP4_COMPLETION_TOKEN *Token, 1123 IN EFI_PXE_BASE_CODE_MODE *Mode, 1124 IN EFI_EVENT TimeoutEvent, 1125 IN UINT16 OpFlags, 1126 IN BOOLEAN *IsDone, 1127 OUT BOOLEAN *IsMatched, 1128 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL, 1129 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL, 1130 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL, 1131 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL 1132 ) 1133 { 1134 EFI_UDP4_RECEIVE_DATA *RxData; 1135 EFI_UDP4_SESSION_DATA *Session; 1136 EFI_STATUS Status; 1137 1138 Token->Status = EFI_NOT_READY; 1139 *IsDone = FALSE; 1140 1141 Status = Udp4->Receive (Udp4, Token); 1142 if (EFI_ERROR (Status)) { 1143 return Status; 1144 } 1145 1146 // 1147 // Poll the UDPv6 read instance if no packet received and no timeout triggered. 1148 // 1149 while (!(*IsDone) && 1150 Token->Status == EFI_NOT_READY && 1151 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { 1152 // 1153 // Poll the token utill reply/ICMPv6 error message received or timeout. 1154 // 1155 Udp4->Poll (Udp4); 1156 if (Token->Status == EFI_ICMP_ERROR || 1157 Token->Status == EFI_NETWORK_UNREACHABLE || 1158 Token->Status == EFI_HOST_UNREACHABLE || 1159 Token->Status == EFI_PROTOCOL_UNREACHABLE || 1160 Token->Status == EFI_PORT_UNREACHABLE) { 1161 break; 1162 } 1163 } 1164 1165 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status; 1166 1167 if (!EFI_ERROR (Status)) { 1168 // 1169 // check whether this packet matches the filters 1170 // 1171 RxData = Token->Packet.RxData; 1172 Session = &RxData->UdpSession; 1173 1174 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags); 1175 1176 if (*IsMatched) { 1177 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags); 1178 } 1179 1180 if (*IsMatched) { 1181 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags); 1182 } 1183 1184 if (*IsMatched) { 1185 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags); 1186 } 1187 1188 if (*IsMatched) { 1189 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags); 1190 } 1191 1192 if (!(*IsMatched)) { 1193 // 1194 // Recycle the receiving buffer if not matched. 1195 // 1196 gBS->SignalEvent (RxData->RecycleSignal); 1197 } 1198 } 1199 1200 return Status; 1201 } 1202 1203 1204 /** 1205 This function is to receive packets using Udp6Read. 1206 1207 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. 1208 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN. 1209 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE. 1210 @param[in] TimeoutEvent The event for timeout. 1211 @param[in] OpFlags The UDP operation flags. 1212 @param[in] IsDone The pointer to the IsDone flag. 1213 @param[out] IsMatched The pointer to the IsMatched flag. 1214 @param[in, out] DestIp The pointer to the destination address. 1215 @param[in, out] DestPort The pointer to the destination port. 1216 @param[in, out] SrcIp The pointer to the source address. 1217 @param[in, out] SrcPort The pointer to the source port. 1218 1219 @retval EFI_SUCCESS Successfully read data using Udp6. 1220 @retval Others Failed to send out data. 1221 1222 **/ 1223 EFI_STATUS 1224 PxeBcUdp6Read ( 1225 IN EFI_UDP6_PROTOCOL *Udp6, 1226 IN EFI_UDP6_COMPLETION_TOKEN *Token, 1227 IN EFI_PXE_BASE_CODE_MODE *Mode, 1228 IN EFI_EVENT TimeoutEvent, 1229 IN UINT16 OpFlags, 1230 IN BOOLEAN *IsDone, 1231 OUT BOOLEAN *IsMatched, 1232 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL, 1233 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL, 1234 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL, 1235 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL 1236 ) 1237 { 1238 EFI_UDP6_RECEIVE_DATA *RxData; 1239 EFI_UDP6_SESSION_DATA *Session; 1240 EFI_STATUS Status; 1241 1242 Token->Status = EFI_NOT_READY; 1243 *IsDone = FALSE; 1244 1245 Status = Udp6->Receive (Udp6, Token); 1246 if (EFI_ERROR (Status)) { 1247 return Status; 1248 } 1249 1250 // 1251 // Poll the UDPv6 read instance if no packet received and no timeout triggered. 1252 // 1253 while (!(*IsDone) && 1254 Token->Status == EFI_NOT_READY && 1255 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { 1256 // 1257 // Poll the token utill reply/ICMPv6 error message received or timeout. 1258 // 1259 Udp6->Poll (Udp6); 1260 if (Token->Status == EFI_ICMP_ERROR || 1261 Token->Status == EFI_NETWORK_UNREACHABLE || 1262 Token->Status == EFI_HOST_UNREACHABLE || 1263 Token->Status == EFI_PROTOCOL_UNREACHABLE || 1264 Token->Status == EFI_PORT_UNREACHABLE) { 1265 break; 1266 } 1267 } 1268 1269 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status; 1270 1271 if (!EFI_ERROR (Status)) { 1272 // 1273 // check whether this packet matches the filters 1274 // 1275 RxData = Token->Packet.RxData; 1276 Session = &RxData->UdpSession; 1277 1278 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags); 1279 1280 if (*IsMatched) { 1281 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags); 1282 } 1283 1284 if (*IsMatched) { 1285 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags); 1286 } 1287 1288 if (*IsMatched) { 1289 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags); 1290 } 1291 1292 if (*IsMatched) { 1293 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags); 1294 } 1295 1296 if (!(*IsMatched)) { 1297 // 1298 // Recycle the receiving buffer if not matched. 1299 // 1300 gBS->SignalEvent (RxData->RecycleSignal); 1301 } 1302 } 1303 1304 return Status; 1305 } 1306 1307 1308 /** 1309 This function is to display the IPv4 address. 1310 1311 @param[in] Ip The pointer to the IPv4 address. 1312 1313 **/ 1314 VOID 1315 PxeBcShowIp4Addr ( 1316 IN EFI_IPv4_ADDRESS *Ip 1317 ) 1318 { 1319 UINTN Index; 1320 1321 for (Index = 0; Index < 4; Index++) { 1322 AsciiPrint ("%d", Ip->Addr[Index]); 1323 if (Index < 3) { 1324 AsciiPrint ("."); 1325 } 1326 } 1327 } 1328 1329 1330 /** 1331 This function is to display the IPv6 address. 1332 1333 @param[in] Ip The pointer to the IPv6 address. 1334 1335 **/ 1336 VOID 1337 PxeBcShowIp6Addr ( 1338 IN EFI_IPv6_ADDRESS *Ip 1339 ) 1340 { 1341 UINTN Index; 1342 1343 for (Index = 0; Index < 16; Index++) { 1344 1345 if (Ip->Addr[Index] != 0) { 1346 AsciiPrint ("%x", Ip->Addr[Index]); 1347 } 1348 Index++; 1349 if (Index > 15) { 1350 return; 1351 } 1352 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) { 1353 AsciiPrint ("0"); 1354 } 1355 AsciiPrint ("%x", Ip->Addr[Index]); 1356 if (Index < 15) { 1357 AsciiPrint (":"); 1358 } 1359 } 1360 } 1361 1362 1363 /** 1364 This function is to convert UINTN to ASCII string with the required formatting. 1365 1366 @param[in] Number Numeric value to be converted. 1367 @param[in] Buffer The pointer to the buffer for ASCII string. 1368 @param[in] Length The length of the required format. 1369 1370 **/ 1371 VOID 1372 PxeBcUintnToAscDecWithFormat ( 1373 IN UINTN Number, 1374 IN UINT8 *Buffer, 1375 IN INTN Length 1376 ) 1377 { 1378 UINTN Remainder; 1379 1380 while (Length > 0) { 1381 Length--; 1382 Remainder = Number % 10; 1383 Number /= 10; 1384 Buffer[Length] = (UINT8) ('0' + Remainder); 1385 } 1386 } 1387 1388 1389 /** 1390 This function is to convert a UINTN to a ASCII string, and return the 1391 actual length of the buffer. 1392 1393 @param[in] Number Numeric value to be converted. 1394 @param[in] Buffer The pointer to the buffer for ASCII string. 1395 @param[in] BufferSize The maxsize of the buffer. 1396 1397 @return Length The actual length of the ASCII string. 1398 1399 **/ 1400 UINTN 1401 PxeBcUintnToAscDec ( 1402 IN UINTN Number, 1403 IN UINT8 *Buffer, 1404 IN UINTN BufferSize 1405 ) 1406 { 1407 UINTN Index; 1408 UINTN Length; 1409 CHAR8 TempStr[64]; 1410 1411 Index = 63; 1412 TempStr[Index] = 0; 1413 1414 do { 1415 Index--; 1416 TempStr[Index] = (CHAR8) ('0' + (Number % 10)); 1417 Number = (UINTN) (Number / 10); 1418 } while (Number != 0); 1419 1420 AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]); 1421 1422 Length = AsciiStrLen ((CHAR8 *) Buffer); 1423 1424 return Length; 1425 } 1426 1427 1428 /** 1429 This function is to convert unicode hex number to a UINT8. 1430 1431 @param[out] Digit The converted UINT8 for output. 1432 @param[in] Char The unicode hex number to be converted. 1433 1434 @retval EFI_SUCCESS Successfully converted the unicode hex. 1435 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex. 1436 1437 **/ 1438 EFI_STATUS 1439 PxeBcUniHexToUint8 ( 1440 OUT UINT8 *Digit, 1441 IN CHAR16 Char 1442 ) 1443 { 1444 if ((Char >= L'0') && (Char <= L'9')) { 1445 *Digit = (UINT8) (Char - L'0'); 1446 return EFI_SUCCESS; 1447 } 1448 1449 if ((Char >= L'A') && (Char <= L'F')) { 1450 *Digit = (UINT8) (Char - L'A' + 0x0A); 1451 return EFI_SUCCESS; 1452 } 1453 1454 if ((Char >= L'a') && (Char <= L'f')) { 1455 *Digit = (UINT8) (Char - L'a' + 0x0A); 1456 return EFI_SUCCESS; 1457 } 1458 1459 return EFI_INVALID_PARAMETER; 1460 } 1461 1462 /** 1463 Calculate the elapsed time. 1464 1465 @param[in] Private The pointer to PXE private data 1466 1467 **/ 1468 VOID 1469 CalcElapsedTime ( 1470 IN PXEBC_PRIVATE_DATA *Private 1471 ) 1472 { 1473 EFI_TIME Time; 1474 UINT64 CurrentStamp; 1475 UINT64 ElapsedTimeValue; 1476 1477 // 1478 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month. 1479 // 1480 ZeroMem (&Time, sizeof (EFI_TIME)); 1481 gRT->GetTime (&Time, NULL); 1482 CurrentStamp = (UINT64) 1483 ( 1484 ((((((Time.Year - 1900) * 360 + 1485 (Time.Month - 1)) * 30 + 1486 (Time.Day - 1)) * 24 + Time.Hour) * 60 + 1487 Time.Minute) * 60 + Time.Second) * 100 1488 + DivU64x32(Time.Nanosecond, 10000000) 1489 ); 1490 1491 // 1492 // Sentinel value of 0 means that this is the first DHCP packet that we are 1493 // sending and that we need to initialize the value. First DHCP Solicit 1494 // gets 0 elapsed-time. Otherwise, calculate based on StartTime. 1495 // 1496 if (Private->ElapsedTime == 0) { 1497 Private->ElapsedTime = CurrentStamp; 1498 } else { 1499 ElapsedTimeValue = CurrentStamp - Private->ElapsedTime; 1500 1501 // 1502 // If elapsed time cannot fit in two bytes, set it to 0xffff. 1503 // 1504 if (ElapsedTimeValue > 0xffff) { 1505 ElapsedTimeValue = 0xffff; 1506 } 1507 // 1508 // Save the elapsed time 1509 // 1510 Private->ElapsedTime = ElapsedTimeValue; 1511 } 1512 } 1513 1514