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