1 /** @file 2 Functions implementation related with DHCPv6 for UefiPxeBc Driver. 3 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> 5 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php. 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "PxeBcImpl.h" 18 19 // 20 // Well-known multi-cast address defined in section-24.1 of rfc-3315 21 // 22 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2 23 // 24 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}}; 25 26 /** 27 Parse out a DHCPv6 option by OptTag, and find the position in buffer. 28 29 @param[in] Buffer The pointer to the option buffer. 30 @param[in] Length Length of the option buffer. 31 @param[in] OptTag The required option tag. 32 33 @retval NULL Failed to parse the required option. 34 @retval Others The postion of the required option in buffer. 35 36 **/ 37 EFI_DHCP6_PACKET_OPTION * 38 PxeBcParseDhcp6Options ( 39 IN UINT8 *Buffer, 40 IN UINT32 Length, 41 IN UINT16 OptTag 42 ) 43 { 44 EFI_DHCP6_PACKET_OPTION *Option; 45 UINT32 Offset; 46 47 Option = (EFI_DHCP6_PACKET_OPTION *) Buffer; 48 Offset = 0; 49 50 // 51 // OpLen and OpCode here are both stored in network order. 52 // 53 while (Offset < Length) { 54 55 if (NTOHS (Option->OpCode) == OptTag) { 56 57 return Option; 58 } 59 60 Offset += (NTOHS(Option->OpLen) + 4); 61 Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset); 62 } 63 64 return NULL; 65 } 66 67 68 /** 69 Build the options buffer for the DHCPv6 request packet. 70 71 @param[in] Private The pointer to PxeBc private data. 72 @param[out] OptList The pointer to the option pointer array. 73 @param[in] Buffer The pointer to the buffer to contain the option list. 74 75 @return Index The count of the built-in options. 76 77 **/ 78 UINT32 79 PxeBcBuildDhcp6Options ( 80 IN PXEBC_PRIVATE_DATA *Private, 81 OUT EFI_DHCP6_PACKET_OPTION **OptList, 82 IN UINT8 *Buffer 83 ) 84 { 85 PXEBC_DHCP6_OPTION_ENTRY OptEnt; 86 UINT32 Index; 87 UINT16 Value; 88 89 Index = 0; 90 OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer; 91 92 // 93 // Append client option request option 94 // 95 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO); 96 OptList[Index]->OpLen = HTONS (6); 97 OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data; 98 OptEnt.Oro->OpCode[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL); 99 OptEnt.Oro->OpCode[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM); 100 OptEnt.Oro->OpCode[2] = HTONS(DHCP6_OPT_DNS_SERVERS); 101 Index++; 102 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 103 104 // 105 // Append client network device interface option 106 // 107 OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI); 108 OptList[Index]->OpLen = HTONS ((UINT16)3); 109 OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data; 110 111 if (Private->Nii != NULL) { 112 OptEnt.Undi->Type = Private->Nii->Type; 113 OptEnt.Undi->MajorVer = Private->Nii->MajorVer; 114 OptEnt.Undi->MinorVer = Private->Nii->MinorVer; 115 } else { 116 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; 117 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; 118 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; 119 } 120 121 Index++; 122 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 123 124 // 125 // Append client system architecture option 126 // 127 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH); 128 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH)); 129 OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data; 130 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); 131 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); 132 Index++; 133 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 134 135 // 136 // Append vendor class option to store the PXE class identifier. 137 // 138 OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS); 139 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS)); 140 OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data; 141 OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM); 142 OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID)); 143 CopyMem ( 144 &OptEnt.VendorClass->ClassId, 145 DEFAULT_CLASS_ID_DATA, 146 sizeof (PXEBC_CLASS_ID) 147 ); 148 PxeBcUintnToAscDecWithFormat ( 149 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, 150 OptEnt.VendorClass->ClassId.ArchitectureType, 151 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType) 152 ); 153 154 if (Private->Nii != NULL) { 155 CopyMem ( 156 OptEnt.VendorClass->ClassId.InterfaceName, 157 Private->Nii->StringId, 158 sizeof (OptEnt.VendorClass->ClassId.InterfaceName) 159 ); 160 PxeBcUintnToAscDecWithFormat ( 161 Private->Nii->MajorVer, 162 OptEnt.VendorClass->ClassId.UndiMajor, 163 sizeof (OptEnt.VendorClass->ClassId.UndiMajor) 164 ); 165 PxeBcUintnToAscDecWithFormat ( 166 Private->Nii->MinorVer, 167 OptEnt.VendorClass->ClassId.UndiMinor, 168 sizeof (OptEnt.VendorClass->ClassId.UndiMinor) 169 ); 170 } 171 172 Index++; 173 174 return Index; 175 } 176 177 178 /** 179 Cache the DHCPv6 packet. 180 181 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet. 182 @param[in] Src The pointer to the DHCPv6 packet to be cached. 183 184 @retval EFI_SUCCESS Packet is copied. 185 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. 186 187 **/ 188 EFI_STATUS 189 PxeBcCacheDhcp6Packet ( 190 IN EFI_DHCP6_PACKET *Dst, 191 IN EFI_DHCP6_PACKET *Src 192 ) 193 { 194 if (Dst->Size < Src->Length) { 195 return EFI_BUFFER_TOO_SMALL; 196 } 197 198 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length); 199 Dst->Length = Src->Length; 200 201 return EFI_SUCCESS; 202 } 203 204 205 /** 206 Free all the nodes in the list for boot file. 207 208 @param[in] Head The pointer to the head of list. 209 210 **/ 211 VOID 212 PxeBcFreeBootFileOption ( 213 IN LIST_ENTRY *Head 214 ) 215 { 216 LIST_ENTRY *Entry; 217 LIST_ENTRY *NextEntry; 218 PXEBC_DHCP6_OPTION_NODE *Node; 219 220 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) { 221 Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link); 222 RemoveEntryList (Entry); 223 FreePool (Node); 224 } 225 } 226 227 /** 228 Retrieve the boot server address using the EFI_DNS6_PROTOCOL. 229 230 @param[in] Private Pointer to PxeBc private data. 231 @param[in] HostName Pointer to buffer containing hostname. 232 @param[out] IpAddress On output, pointer to buffer containing IPv6 address. 233 234 @retval EFI_SUCCESS Operation succeeded. 235 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. 236 @retval EFI_DEVICE_ERROR An unexpected network error occurred. 237 @retval Others Other errors as indicated. 238 239 **/ 240 EFI_STATUS 241 PxeBcDns6 ( 242 IN PXEBC_PRIVATE_DATA *Private, 243 IN CHAR16 *HostName, 244 OUT EFI_IPv6_ADDRESS *IpAddress 245 ) 246 { 247 EFI_STATUS Status; 248 EFI_DNS6_PROTOCOL *Dns6; 249 EFI_DNS6_CONFIG_DATA Dns6ConfigData; 250 EFI_DNS6_COMPLETION_TOKEN Token; 251 EFI_HANDLE Dns6Handle; 252 EFI_IPv6_ADDRESS *DnsServerList; 253 BOOLEAN IsDone; 254 255 Dns6 = NULL; 256 Dns6Handle = NULL; 257 DnsServerList = Private->DnsServer; 258 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); 259 260 // 261 // Create a DNSv6 child instance and get the protocol. 262 // 263 Status = NetLibCreateServiceChild ( 264 Private->Controller, 265 Private->Image, 266 &gEfiDns6ServiceBindingProtocolGuid, 267 &Dns6Handle 268 ); 269 if (EFI_ERROR (Status)) { 270 goto Exit; 271 } 272 273 Status = gBS->OpenProtocol ( 274 Dns6Handle, 275 &gEfiDns6ProtocolGuid, 276 (VOID **) &Dns6, 277 Private->Image, 278 Private->Controller, 279 EFI_OPEN_PROTOCOL_BY_DRIVER 280 ); 281 if (EFI_ERROR (Status)) { 282 goto Exit; 283 } 284 285 // 286 // Configure DNS6 instance for the DNS server address and protocol. 287 // 288 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); 289 Dns6ConfigData.DnsServerCount = 1; 290 Dns6ConfigData.DnsServerList = DnsServerList; 291 Dns6ConfigData.EnableDnsCache = TRUE; 292 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; 293 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6); 294 Status = Dns6->Configure ( 295 Dns6, 296 &Dns6ConfigData 297 ); 298 if (EFI_ERROR (Status)) { 299 goto Exit; 300 } 301 302 Token.Status = EFI_NOT_READY; 303 IsDone = FALSE; 304 // 305 // Create event to set the IsDone flag when name resolution is finished. 306 // 307 Status = gBS->CreateEvent ( 308 EVT_NOTIFY_SIGNAL, 309 TPL_NOTIFY, 310 PxeBcCommonNotify, 311 &IsDone, 312 &Token.Event 313 ); 314 if (EFI_ERROR (Status)) { 315 goto Exit; 316 } 317 318 // 319 // Start asynchronous name resolution. 320 // 321 Status = Dns6->HostNameToIp (Dns6, HostName, &Token); 322 if (EFI_ERROR (Status)) { 323 goto Exit; 324 } 325 326 while (!IsDone) { 327 Dns6->Poll (Dns6); 328 } 329 330 // 331 // Name resolution is done, check result. 332 // 333 Status = Token.Status; 334 if (!EFI_ERROR (Status)) { 335 if (Token.RspData.H2AData == NULL) { 336 Status = EFI_DEVICE_ERROR; 337 goto Exit; 338 } 339 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { 340 Status = EFI_DEVICE_ERROR; 341 goto Exit; 342 } 343 // 344 // We just return the first IPv6 address from DNS protocol. 345 // 346 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); 347 Status = EFI_SUCCESS; 348 } 349 350 Exit: 351 FreePool (HostName); 352 353 if (Token.Event != NULL) { 354 gBS->CloseEvent (Token.Event); 355 } 356 if (Token.RspData.H2AData != NULL) { 357 if (Token.RspData.H2AData->IpList != NULL) { 358 FreePool (Token.RspData.H2AData->IpList); 359 } 360 FreePool (Token.RspData.H2AData); 361 } 362 363 if (Dns6 != NULL) { 364 Dns6->Configure (Dns6, NULL); 365 366 gBS->CloseProtocol ( 367 Dns6Handle, 368 &gEfiDns6ProtocolGuid, 369 Private->Image, 370 Private->Controller 371 ); 372 } 373 374 if (Dns6Handle != NULL) { 375 NetLibDestroyServiceChild ( 376 Private->Controller, 377 Private->Image, 378 &gEfiDns6ServiceBindingProtocolGuid, 379 Dns6Handle 380 ); 381 } 382 383 if (DnsServerList != NULL) { 384 FreePool (DnsServerList); 385 } 386 387 return Status; 388 } 389 390 /** 391 Parse the Boot File URL option. 392 393 @param[in] Private Pointer to PxeBc private data. 394 @param[out] FileName The pointer to the boot file name. 395 @param[in, out] SrvAddr The pointer to the boot server address. 396 @param[in] BootFile The pointer to the boot file URL option data. 397 @param[in] Length The length of the boot file URL option data. 398 399 @retval EFI_ABORTED User cancel operation. 400 @retval EFI_SUCCESS Selected the boot menu successfully. 401 @retval EFI_NOT_READY Read the input key from the keybroad has not finish. 402 403 **/ 404 EFI_STATUS 405 PxeBcExtractBootFileUrl ( 406 IN PXEBC_PRIVATE_DATA *Private, 407 OUT UINT8 **FileName, 408 IN OUT EFI_IPv6_ADDRESS *SrvAddr, 409 IN CHAR8 *BootFile, 410 IN UINT16 Length 411 ) 412 { 413 UINT16 PrefixLen; 414 CHAR8 *BootFileNamePtr; 415 CHAR8 *BootFileName; 416 UINT16 BootFileNameLen; 417 CHAR8 *TmpStr; 418 CHAR8 TmpChar; 419 CHAR8 *ServerAddressOption; 420 CHAR8 *ServerAddress; 421 CHAR8 *ModeStr; 422 CHAR16 *HostName; 423 BOOLEAN IpExpressedUrl; 424 UINTN Len; 425 EFI_STATUS Status; 426 427 IpExpressedUrl = TRUE; 428 // 429 // The format of the Boot File URL option is: 430 // 431 // 0 1 2 3 432 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 433 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 434 // | OPT_BOOTFILE_URL | option-len | 435 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 436 // | | 437 // . bootfile-url (variable length) . 438 // | | 439 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 440 // 441 442 // 443 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be 444 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME 445 // As an example where the BOOTFILE_NAME is the EFI loader and 446 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address. 447 // 448 PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); 449 450 if (Length <= PrefixLen || 451 CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) { 452 return EFI_NOT_FOUND; 453 } 454 455 BootFile = BootFile + PrefixLen; 456 Length = (UINT16) (Length - PrefixLen); 457 458 TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1); 459 if (TmpStr == NULL) { 460 return EFI_OUT_OF_RESOURCES; 461 } 462 463 CopyMem (TmpStr, BootFile, Length); 464 TmpStr[Length] = '\0'; 465 466 // 467 // Get the part of SERVER_ADDRESS string. 468 // 469 ServerAddressOption = TmpStr; 470 if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) { 471 ServerAddressOption ++; 472 ServerAddress = ServerAddressOption; 473 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) { 474 ServerAddress++; 475 } 476 477 if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { 478 FreePool (TmpStr); 479 return EFI_INVALID_PARAMETER; 480 } 481 482 *ServerAddress = '\0'; 483 484 // 485 // Convert the string of server address to Ipv6 address format and store it. 486 // 487 Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); 488 if (EFI_ERROR (Status)) { 489 FreePool (TmpStr); 490 return Status; 491 } 492 493 } else { 494 IpExpressedUrl = FALSE; 495 ServerAddress = ServerAddressOption; 496 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { 497 ServerAddress++; 498 } 499 500 if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { 501 FreePool (TmpStr); 502 return EFI_INVALID_PARAMETER; 503 } 504 *ServerAddress = '\0'; 505 506 Len = AsciiStrSize (ServerAddressOption); 507 HostName = AllocateZeroPool (Len * sizeof (CHAR16)); 508 if (HostName == NULL) { 509 FreePool (TmpStr); 510 return EFI_OUT_OF_RESOURCES; 511 } 512 AsciiStrToUnicodeStrS ( 513 ServerAddressOption, 514 HostName, 515 Len 516 ); 517 518 // 519 // Perform DNS resolution. 520 // 521 Status = PxeBcDns6 (Private,HostName, SrvAddr); 522 if (EFI_ERROR (Status)) { 523 FreePool (TmpStr); 524 return Status; 525 } 526 } 527 528 // 529 // Get the part of BOOTFILE_NAME string. 530 // 531 BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1); 532 if (IpExpressedUrl) { 533 if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { 534 FreePool (TmpStr); 535 return EFI_INVALID_PARAMETER; 536 } 537 ++BootFileNamePtr; 538 } 539 540 BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1); 541 if (BootFileNameLen != 0 || FileName != NULL) { 542 // 543 // Remove trailing mode=octet if present and ignore. All other modes are 544 // invalid for netboot6, so reject them. 545 // 546 ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet"); 547 if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') { 548 *ModeStr = '\0'; 549 } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) { 550 return EFI_INVALID_PARAMETER; 551 } 552 553 // 554 // Extract boot file name from URL. 555 // 556 BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen); 557 if (BootFileName == NULL) { 558 FreePool (TmpStr); 559 return EFI_OUT_OF_RESOURCES; 560 } 561 *FileName = (UINT8*) BootFileName; 562 563 // 564 // Decode percent-encoding in boot file name. 565 // 566 while (*BootFileNamePtr != '\0') { 567 if (*BootFileNamePtr == '%') { 568 TmpChar = *(BootFileNamePtr+ 3); 569 *(BootFileNamePtr+ 3) = '\0'; 570 *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1)); 571 BootFileName++; 572 *(BootFileNamePtr+ 3) = TmpChar; 573 BootFileNamePtr += 3; 574 } else { 575 *BootFileName = *BootFileNamePtr; 576 BootFileName++; 577 BootFileNamePtr++; 578 } 579 } 580 *BootFileName = '\0'; 581 } 582 583 FreePool (TmpStr); 584 585 return EFI_SUCCESS; 586 } 587 588 589 /** 590 Parse the Boot File Parameter option. 591 592 @param[in] BootFilePara The pointer to boot file parameter option data. 593 @param[out] BootFileSize The pointer to the parsed boot file size. 594 595 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option. 596 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option. 597 598 **/ 599 EFI_STATUS 600 PxeBcExtractBootFileParam ( 601 IN CHAR8 *BootFilePara, 602 OUT UINT16 *BootFileSize 603 ) 604 { 605 UINT16 Length; 606 UINT8 Index; 607 UINT8 Digit; 608 UINT32 Size; 609 610 CopyMem (&Length, BootFilePara, sizeof (UINT16)); 611 Length = NTOHS (Length); 612 613 // 614 // The BootFile Size should be 1~5 byte ASCII strings 615 // 616 if (Length < 1 || Length > 5) { 617 return EFI_NOT_FOUND; 618 } 619 620 // 621 // Extract the value of BootFile Size. 622 // 623 BootFilePara = BootFilePara + sizeof (UINT16); 624 Size = 0; 625 for (Index = 0; Index < Length; Index++) { 626 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) { 627 return EFI_NOT_FOUND; 628 } 629 630 Size = (Size + Digit) * 10; 631 } 632 633 Size = Size / 10; 634 if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) { 635 return EFI_NOT_FOUND; 636 } 637 638 *BootFileSize = (UINT16) Size; 639 return EFI_SUCCESS; 640 } 641 642 643 /** 644 Parse the cached DHCPv6 packet, including all the options. 645 646 @param[in] Cache6 The pointer to a cached DHCPv6 packet. 647 648 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully. 649 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet. 650 651 **/ 652 EFI_STATUS 653 PxeBcParseDhcp6Packet ( 654 IN PXEBC_DHCP6_PACKET_CACHE *Cache6 655 ) 656 { 657 EFI_DHCP6_PACKET *Offer; 658 EFI_DHCP6_PACKET_OPTION **Options; 659 EFI_DHCP6_PACKET_OPTION *Option; 660 PXEBC_OFFER_TYPE OfferType; 661 BOOLEAN IsProxyOffer; 662 BOOLEAN IsPxeOffer; 663 UINT32 Offset; 664 UINT32 Length; 665 UINT32 EnterpriseNum; 666 667 IsProxyOffer = TRUE; 668 IsPxeOffer = FALSE; 669 Offer = &Cache6->Packet.Offer; 670 Options = Cache6->OptList; 671 672 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList)); 673 674 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option); 675 Offset = 0; 676 Length = GET_DHCP6_OPTION_SIZE (Offer); 677 678 // 679 // OpLen and OpCode here are both stored in network order, since they are from original packet. 680 // 681 while (Offset < Length) { 682 683 if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) { 684 Options[PXEBC_DHCP6_IDX_IA_NA] = Option; 685 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) { 686 // 687 // The server sends this option to inform the client about an URL to a boot file. 688 // 689 Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option; 690 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) { 691 Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option; 692 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) { 693 Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option; 694 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) { 695 Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; 696 } 697 698 Offset += (NTOHS (Option->OpLen) + 4); 699 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); 700 } 701 702 // 703 // The offer with assigned client address is NOT a proxy offer. 704 // An ia_na option, embeded with valid ia_addr option and a status_code of success. 705 // 706 Option = Options[PXEBC_DHCP6_IDX_IA_NA]; 707 if (Option != NULL) { 708 Option = PxeBcParseDhcp6Options ( 709 Option->Data + 12, 710 NTOHS (Option->OpLen), 711 DHCP6_OPT_STATUS_CODE 712 ); 713 if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { 714 IsProxyOffer = FALSE; 715 } 716 } 717 718 // 719 // The offer with "PXEClient" is a pxe offer. 720 // 721 Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS]; 722 EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM); 723 724 if (Option != NULL && 725 NTOHS(Option->OpLen) >= 13 && 726 CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 && 727 CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) { 728 IsPxeOffer = TRUE; 729 } 730 731 // 732 // Determine offer type of the dhcp6 packet. 733 // 734 if (IsPxeOffer) { 735 // 736 // It's a binl offer only with PXEClient. 737 // 738 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl; 739 } else { 740 // 741 // It's a dhcp only offer, which is a pure dhcp6 offer packet. 742 // 743 OfferType = PxeOfferTypeDhcpOnly; 744 } 745 746 Cache6->OfferType = OfferType; 747 748 return EFI_SUCCESS; 749 } 750 751 752 /** 753 Cache the DHCPv6 ack packet, and parse it on demand. 754 755 @param[in] Private The pointer to PxeBc private data. 756 @param[in] Ack The pointer to the DHCPv6 ack packet. 757 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data. 758 759 @retval EFI_SUCCESS Cache and parse the packet successfully. 760 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. 761 762 **/ 763 EFI_STATUS 764 PxeBcCopyDhcp6Ack ( 765 IN PXEBC_PRIVATE_DATA *Private, 766 IN EFI_DHCP6_PACKET *Ack, 767 IN BOOLEAN Verified 768 ) 769 { 770 EFI_PXE_BASE_CODE_MODE *Mode; 771 EFI_STATUS Status; 772 773 Mode = Private->PxeBc.Mode; 774 775 Status = PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack); 776 if (EFI_ERROR (Status)) { 777 return Status; 778 } 779 780 if (Verified) { 781 // 782 // Parse the ack packet and store it into mode data if needed. 783 // 784 PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6); 785 CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length); 786 Mode->DhcpAckReceived = TRUE; 787 } 788 789 return EFI_SUCCESS; 790 } 791 792 793 /** 794 Cache the DHCPv6 proxy offer packet according to the received order. 795 796 @param[in] Private The pointer to PxeBc private data. 797 @param[in] OfferIndex The received order of offer packets. 798 799 @retval EFI_SUCCESS Cache and parse the packet successfully. 800 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. 801 802 **/ 803 EFI_STATUS 804 PxeBcCopyDhcp6Proxy ( 805 IN PXEBC_PRIVATE_DATA *Private, 806 IN UINT32 OfferIndex 807 ) 808 { 809 EFI_PXE_BASE_CODE_MODE *Mode; 810 EFI_DHCP6_PACKET *Offer; 811 EFI_STATUS Status; 812 813 ASSERT (OfferIndex < Private->OfferNum); 814 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); 815 816 Mode = Private->PxeBc.Mode; 817 Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer; 818 819 // 820 // Cache the proxy offer packet and parse it. 821 // 822 Status = PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer); 823 if (EFI_ERROR(Status)) { 824 return Status; 825 } 826 PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6); 827 828 // 829 // Store this packet into mode data. 830 // 831 CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length); 832 Mode->ProxyOfferReceived = TRUE; 833 834 return EFI_SUCCESS; 835 } 836 837 /** 838 Seek the address of the first byte of the option header. 839 840 @param[in] Buf The pointer to the buffer. 841 @param[in] SeekLen The length to seek. 842 @param[in] OptType The option type. 843 844 @retval NULL If it failed to seek the option. 845 @retval others The position to the option. 846 847 **/ 848 UINT8 * 849 PxeBcDhcp6SeekOption ( 850 IN UINT8 *Buf, 851 IN UINT32 SeekLen, 852 IN UINT16 OptType 853 ) 854 { 855 UINT8 *Cursor; 856 UINT8 *Option; 857 UINT16 DataLen; 858 UINT16 OpCode; 859 860 Option = NULL; 861 Cursor = Buf; 862 863 while (Cursor < Buf + SeekLen) { 864 OpCode = ReadUnaligned16 ((UINT16 *) Cursor); 865 if (OpCode == HTONS (OptType)) { 866 Option = Cursor; 867 break; 868 } 869 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); 870 Cursor += (DataLen + 4); 871 } 872 873 return Option; 874 } 875 876 877 /** 878 Build and send out the request packet for the bootfile, and parse the reply. 879 880 @param[in] Private The pointer to PxeBc private data. 881 @param[in] Index PxeBc option boot item type. 882 883 @retval EFI_SUCCESS Successfully discovered the boot file. 884 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. 885 @retval EFI_NOT_FOUND Can't get the PXE reply packet. 886 @retval Others Failed to discover the boot file. 887 888 **/ 889 EFI_STATUS 890 PxeBcRequestBootService ( 891 IN PXEBC_PRIVATE_DATA *Private, 892 IN UINT32 Index 893 ) 894 { 895 EFI_PXE_BASE_CODE_UDP_PORT SrcPort; 896 EFI_PXE_BASE_CODE_UDP_PORT DestPort; 897 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; 898 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; 899 UINTN DiscoverLen; 900 EFI_DHCP6_PACKET *Request; 901 UINTN RequestLen; 902 EFI_DHCP6_PACKET *Reply; 903 UINT8 *RequestOpt; 904 UINT8 *DiscoverOpt; 905 UINTN ReadSize; 906 UINT16 OpFlags; 907 UINT16 OpCode; 908 UINT16 OpLen; 909 EFI_STATUS Status; 910 EFI_DHCP6_PACKET *ProxyOffer; 911 UINT8 *Option; 912 913 PxeBc = &Private->PxeBc; 914 Request = Private->Dhcp6Request; 915 ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; 916 SrcPort = PXEBC_BS_DISCOVER_PORT; 917 DestPort = PXEBC_BS_DISCOVER_PORT; 918 OpFlags = 0; 919 920 if (Request == NULL) { 921 return EFI_DEVICE_ERROR; 922 } 923 924 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); 925 if (Discover == NULL) { 926 return EFI_OUT_OF_RESOURCES; 927 } 928 929 // 930 // Build the request packet by the cached request packet before. 931 // 932 Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId; 933 Discover->MessageType = Request->Dhcp6.Header.MessageType; 934 RequestOpt = Request->Dhcp6.Option; 935 DiscoverOpt = Discover->DhcpOptions; 936 DiscoverLen = sizeof (EFI_DHCP6_HEADER); 937 RequestLen = DiscoverLen; 938 939 // 940 // Find Server ID Option from ProxyOffer. 941 // 942 Option = PxeBcDhcp6SeekOption ( 943 ProxyOffer->Dhcp6.Option, 944 ProxyOffer->Length - 4, 945 DHCP6_OPT_SERVER_ID 946 ); 947 if (Option == NULL) { 948 return EFI_NOT_FOUND; 949 } 950 951 // 952 // Add Server ID Option. 953 // 954 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen); 955 CopyMem (DiscoverOpt, Option, OpLen + 4); 956 DiscoverOpt += (OpLen + 4); 957 DiscoverLen += (OpLen + 4); 958 959 while (RequestLen < Request->Length) { 960 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); 961 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); 962 if (OpCode != EFI_DHCP6_IA_TYPE_NA && 963 OpCode != EFI_DHCP6_IA_TYPE_TA && 964 OpCode != DHCP6_OPT_SERVER_ID 965 ) { 966 // 967 // Copy all the options except IA option and Server ID 968 // 969 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); 970 DiscoverOpt += (OpLen + 4); 971 DiscoverLen += (OpLen + 4); 972 } 973 RequestOpt += (OpLen + 4); 974 RequestLen += (OpLen + 4); 975 } 976 977 // 978 // Update Elapsed option in the package 979 // 980 Option = PxeBcDhcp6SeekOption ( 981 Discover->DhcpOptions, 982 (UINT32)(RequestLen - 4), 983 DHCP6_OPT_ELAPSED_TIME 984 ); 985 if (Option != NULL) { 986 CalcElapsedTime (Private); 987 WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime)); 988 } 989 990 Status = PxeBc->UdpWrite ( 991 PxeBc, 992 OpFlags, 993 &Private->ServerIp, 994 &DestPort, 995 NULL, 996 &Private->StationIp, 997 &SrcPort, 998 NULL, 999 NULL, 1000 &DiscoverLen, 1001 (VOID *) Discover 1002 ); 1003 1004 if (EFI_ERROR (Status)) { 1005 return Status; 1006 } 1007 1008 // 1009 // Cache the right PXE reply packet here, set valid flag later. 1010 // Especially for PXE discover packet, store it into mode data here. 1011 // 1012 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; 1013 ReadSize = (UINTN) Reply->Size; 1014 1015 // 1016 // Start Udp6Read instance 1017 // 1018 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); 1019 if (EFI_ERROR (Status)) { 1020 return Status; 1021 } 1022 1023 Status = PxeBc->UdpRead ( 1024 PxeBc, 1025 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, 1026 NULL, 1027 &SrcPort, 1028 &Private->ServerIp, 1029 &DestPort, 1030 NULL, 1031 NULL, 1032 &ReadSize, 1033 (VOID *) &Reply->Dhcp6 1034 ); 1035 // 1036 // Stop Udp6Read instance 1037 // 1038 Private->Udp6Read->Configure (Private->Udp6Read, NULL); 1039 1040 if (EFI_ERROR (Status)) { 1041 return Status; 1042 } 1043 1044 // 1045 // Update length 1046 // 1047 Reply->Length = (UINT32) ReadSize; 1048 1049 return EFI_SUCCESS; 1050 } 1051 1052 1053 /** 1054 Retry to request bootfile name by the BINL offer. 1055 1056 @param[in] Private The pointer to PxeBc private data. 1057 @param[in] Index The received order of offer packets. 1058 1059 @retval EFI_SUCCESS Successfully retried a request for the bootfile name. 1060 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name. 1061 1062 **/ 1063 EFI_STATUS 1064 PxeBcRetryDhcp6Binl ( 1065 IN PXEBC_PRIVATE_DATA *Private, 1066 IN UINT32 Index 1067 ) 1068 { 1069 EFI_PXE_BASE_CODE_MODE *Mode; 1070 PXEBC_DHCP6_PACKET_CACHE *Offer; 1071 PXEBC_DHCP6_PACKET_CACHE *Cache6; 1072 EFI_STATUS Status; 1073 1074 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 1075 ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl || 1076 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl); 1077 1078 Mode = Private->PxeBc.Mode; 1079 Private->IsDoDiscover = FALSE; 1080 Offer = &Private->OfferBuffer[Index].Dhcp6; 1081 if (Offer->OfferType == PxeOfferTypeDhcpBinl) { 1082 // 1083 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead. 1084 // 1085 CopyMem ( 1086 &Private->ServerIp.v6, 1087 &mAllDhcpRelayAndServersAddress, 1088 sizeof (EFI_IPv6_ADDRESS) 1089 ); 1090 } else { 1091 ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); 1092 // 1093 // Parse out the next server address from the last offer, and store it 1094 // 1095 Status = PxeBcExtractBootFileUrl ( 1096 Private, 1097 &Private->BootFileName, 1098 &Private->ServerIp.v6, 1099 (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), 1100 NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) 1101 ); 1102 if (EFI_ERROR (Status)) { 1103 return Status; 1104 } 1105 } 1106 1107 // 1108 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer. 1109 // 1110 Status = PxeBcRequestBootService (Private, Index); 1111 1112 if (EFI_ERROR (Status)) { 1113 return Status; 1114 } 1115 1116 Cache6 = &Private->ProxyOffer.Dhcp6; 1117 Status = PxeBcParseDhcp6Packet (Cache6); 1118 if (EFI_ERROR (Status)) { 1119 return Status; 1120 } 1121 1122 if (Cache6->OfferType != PxeOfferTypeProxyPxe10 && 1123 Cache6->OfferType != PxeOfferTypeProxyWfm11a && 1124 Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) { 1125 // 1126 // This BINL ack doesn't have discovery option set or multicast option set 1127 // or bootfile name specified. 1128 // 1129 return EFI_DEVICE_ERROR; 1130 } 1131 1132 Mode->ProxyOfferReceived = TRUE; 1133 CopyMem ( 1134 &Mode->ProxyOffer.Dhcpv6, 1135 &Cache6->Packet.Offer.Dhcp6, 1136 Cache6->Packet.Offer.Length 1137 ); 1138 1139 return EFI_SUCCESS; 1140 } 1141 1142 1143 /** 1144 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount. 1145 1146 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1147 @param[in] RcvdOffer The pointer to the received offer packet. 1148 1149 @retval EFI_SUCCESS Cache and parse the packet successfully. 1150 @retval Others Operation failed. 1151 **/ 1152 EFI_STATUS 1153 PxeBcCacheDhcp6Offer ( 1154 IN PXEBC_PRIVATE_DATA *Private, 1155 IN EFI_DHCP6_PACKET *RcvdOffer 1156 ) 1157 { 1158 PXEBC_DHCP6_PACKET_CACHE *Cache6; 1159 EFI_DHCP6_PACKET *Offer; 1160 PXEBC_OFFER_TYPE OfferType; 1161 EFI_STATUS Status; 1162 1163 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6; 1164 Offer = &Cache6->Packet.Offer; 1165 1166 // 1167 // Cache the content of DHCPv6 packet firstly. 1168 // 1169 Status = PxeBcCacheDhcp6Packet (Offer, RcvdOffer); 1170 if (EFI_ERROR (Status)) { 1171 return Status; 1172 } 1173 1174 // 1175 // Validate the DHCPv6 packet, and parse the options and offer type. 1176 // 1177 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) { 1178 return EFI_ABORTED; 1179 } 1180 1181 // 1182 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. 1183 // 1184 OfferType = Cache6->OfferType; 1185 ASSERT (OfferType < PxeOfferTypeMax); 1186 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM); 1187 1188 if (IS_PROXY_OFFER (OfferType)) { 1189 // 1190 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer. 1191 // 1192 Private->IsProxyRecved = TRUE; 1193 1194 if (OfferType == PxeOfferTypeProxyBinl) { 1195 // 1196 // Cache all proxy BINL offers. 1197 // 1198 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 1199 Private->OfferCount[OfferType]++; 1200 } else if (Private->OfferCount[OfferType] > 0) { 1201 // 1202 // Only cache the first PXE10/WFM11a offer, and discard the others. 1203 // 1204 Private->OfferIndex[OfferType][0] = Private->OfferNum; 1205 Private->OfferCount[OfferType] = 1; 1206 } else { 1207 return EFI_ABORTED; 1208 } 1209 } else { 1210 // 1211 // It's a DHCPv6 offer with yiaddr, and cache them all. 1212 // 1213 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 1214 Private->OfferCount[OfferType]++; 1215 } 1216 1217 Private->OfferNum++; 1218 1219 return EFI_SUCCESS; 1220 } 1221 1222 1223 /** 1224 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType. 1225 1226 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1227 1228 **/ 1229 VOID 1230 PxeBcSelectDhcp6Offer ( 1231 IN PXEBC_PRIVATE_DATA *Private 1232 ) 1233 { 1234 UINT32 Index; 1235 UINT32 OfferIndex; 1236 PXEBC_OFFER_TYPE OfferType; 1237 1238 Private->SelectIndex = 0; 1239 1240 if (Private->IsOfferSorted) { 1241 // 1242 // Select offer by default policy. 1243 // 1244 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) { 1245 // 1246 // 1. DhcpPxe10 offer 1247 // 1248 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1; 1249 1250 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { 1251 // 1252 // 2. DhcpWfm11a offer 1253 // 1254 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1; 1255 1256 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 1257 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { 1258 // 1259 // 3. DhcpOnly offer and ProxyPxe10 offer. 1260 // 1261 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 1262 Private->SelectProxyType = PxeOfferTypeProxyPxe10; 1263 1264 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 1265 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { 1266 // 1267 // 4. DhcpOnly offer and ProxyWfm11a offer. 1268 // 1269 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 1270 Private->SelectProxyType = PxeOfferTypeProxyWfm11a; 1271 1272 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { 1273 // 1274 // 5. DhcpBinl offer. 1275 // 1276 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1; 1277 1278 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 1279 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { 1280 // 1281 // 6. DhcpOnly offer and ProxyBinl offer. 1282 // 1283 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 1284 Private->SelectProxyType = PxeOfferTypeProxyBinl; 1285 1286 } else { 1287 // 1288 // 7. DhcpOnly offer with bootfilename. 1289 // 1290 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) { 1291 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index]; 1292 if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) { 1293 Private->SelectIndex = OfferIndex + 1; 1294 break; 1295 } 1296 } 1297 } 1298 } else { 1299 // 1300 // Select offer by received order. 1301 // 1302 for (Index = 0; Index < Private->OfferNum; Index++) { 1303 1304 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType; 1305 1306 if (IS_PROXY_OFFER (OfferType)) { 1307 // 1308 // Skip proxy offers 1309 // 1310 continue; 1311 } 1312 1313 if (!Private->IsProxyRecved && 1314 OfferType == PxeOfferTypeDhcpOnly && 1315 Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) { 1316 // 1317 // Skip if DhcpOnly offer without any other proxy offers or bootfilename. 1318 // 1319 continue; 1320 } 1321 1322 Private->SelectIndex = Index + 1; 1323 break; 1324 } 1325 } 1326 } 1327 1328 1329 /** 1330 Handle the DHCPv6 offer packet. 1331 1332 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1333 1334 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. 1335 @retval EFI_NO_RESPONSE No response to the following request packet. 1336 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. 1337 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet. 1338 1339 **/ 1340 EFI_STATUS 1341 PxeBcHandleDhcp6Offer ( 1342 IN PXEBC_PRIVATE_DATA *Private 1343 ) 1344 { 1345 PXEBC_DHCP6_PACKET_CACHE *Cache6; 1346 EFI_STATUS Status; 1347 PXEBC_OFFER_TYPE OfferType; 1348 UINT32 ProxyIndex; 1349 UINT32 SelectIndex; 1350 UINT32 Index; 1351 1352 ASSERT (Private->SelectIndex > 0); 1353 SelectIndex = (UINT32) (Private->SelectIndex - 1); 1354 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); 1355 Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6; 1356 Status = EFI_SUCCESS; 1357 1358 // 1359 // First try to cache DNS server address if DHCP6 offer provides. 1360 // 1361 if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { 1362 Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); 1363 if (Private->DnsServer == NULL) { 1364 return EFI_OUT_OF_RESOURCES; 1365 } 1366 CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); 1367 } 1368 1369 if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { 1370 // 1371 // DhcpBinl offer is selected, so need try to request bootfilename by this offer. 1372 // 1373 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) { 1374 Status = EFI_NO_RESPONSE; 1375 } 1376 } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) { 1377 1378 if (Private->IsProxyRecved) { 1379 // 1380 // DhcpOnly offer is selected, so need try to request bootfilename. 1381 // 1382 ProxyIndex = 0; 1383 if (Private->IsOfferSorted) { 1384 // 1385 // The proxy offer should be determined if select by default policy. 1386 // IsOfferSorted means all offers are labeled by OfferIndex. 1387 // 1388 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0); 1389 1390 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) { 1391 // 1392 // Try all the cached ProxyBinl offer one by one to request bootfilename. 1393 // 1394 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) { 1395 1396 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index]; 1397 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) { 1398 break; 1399 } 1400 } 1401 if (Index == Private->OfferCount[Private->SelectProxyType]) { 1402 Status = EFI_NO_RESPONSE; 1403 } 1404 } else { 1405 // 1406 // For other proxy offers (pxe10 or wfm11a), only one is buffered. 1407 // 1408 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0]; 1409 } 1410 } else { 1411 // 1412 // The proxy offer should not be determined if select by received order. 1413 // 1414 Status = EFI_NO_RESPONSE; 1415 1416 for (Index = 0; Index < Private->OfferNum; Index++) { 1417 1418 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType; 1419 1420 if (!IS_PROXY_OFFER (OfferType)) { 1421 // 1422 // Skip non proxy dhcp offers. 1423 // 1424 continue; 1425 } 1426 1427 if (OfferType == PxeOfferTypeProxyBinl) { 1428 // 1429 // Try all the cached ProxyBinl offer one by one to request bootfilename. 1430 // 1431 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) { 1432 continue; 1433 } 1434 } 1435 1436 Private->SelectProxyType = OfferType; 1437 ProxyIndex = Index; 1438 Status = EFI_SUCCESS; 1439 break; 1440 } 1441 } 1442 1443 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) { 1444 // 1445 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it. 1446 // 1447 Status = PxeBcCopyDhcp6Proxy (Private, ProxyIndex); 1448 } 1449 } else { 1450 // 1451 // Othewise, the bootfilename must be included in DhcpOnly offer. 1452 // 1453 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); 1454 } 1455 } 1456 1457 if (!EFI_ERROR (Status)) { 1458 // 1459 // All PXE boot information is ready by now. 1460 // 1461 Status = PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE); 1462 Private->PxeBc.Mode->DhcpDiscoverValid = TRUE; 1463 } 1464 1465 return Status; 1466 } 1467 1468 1469 /** 1470 Unregister the address by Ip6Config protocol. 1471 1472 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1473 1474 **/ 1475 VOID 1476 PxeBcUnregisterIp6Address ( 1477 IN PXEBC_PRIVATE_DATA *Private 1478 ) 1479 { 1480 if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) { 1481 // 1482 // PXE driver change the policy of IP6 driver, it's a chance to recover. 1483 // Keep the point and there is no enough requirements to do recovery. 1484 // 1485 } 1486 } 1487 1488 /** 1489 Check whether IP driver could route the message which will be sent to ServerIp address. 1490 1491 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid 1492 route is found in IP6 route table, the address will be filed in GatewayAddr and return. 1493 1494 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1495 @param[in] TimeOutInSecond Timeout value in seconds. 1496 @param[out] GatewayAddr Pointer to store the gateway IP address. 1497 1498 @retval EFI_SUCCESS Found a valid gateway address successfully. 1499 @retval EFI_TIMEOUT The operation is time out. 1500 @retval Other Unexpect error happened. 1501 1502 **/ 1503 EFI_STATUS 1504 PxeBcCheckRouteTable ( 1505 IN PXEBC_PRIVATE_DATA *Private, 1506 IN UINTN TimeOutInSecond, 1507 OUT EFI_IPv6_ADDRESS *GatewayAddr 1508 ) 1509 { 1510 EFI_STATUS Status; 1511 EFI_IP6_PROTOCOL *Ip6; 1512 EFI_IP6_MODE_DATA Ip6ModeData; 1513 UINTN Index; 1514 EFI_EVENT TimeOutEvt; 1515 UINTN RetryCount; 1516 BOOLEAN GatewayIsFound; 1517 1518 ASSERT (GatewayAddr != NULL); 1519 ASSERT (Private != NULL); 1520 1521 Ip6 = Private->Ip6; 1522 GatewayIsFound = FALSE; 1523 RetryCount = 0; 1524 TimeOutEvt = NULL; 1525 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS)); 1526 1527 while (TRUE) { 1528 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL); 1529 if (EFI_ERROR (Status)) { 1530 goto ON_EXIT; 1531 } 1532 1533 // 1534 // Find out the gateway address which can route the message which send to ServerIp. 1535 // 1536 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) { 1537 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) { 1538 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway); 1539 GatewayIsFound = TRUE; 1540 break; 1541 } 1542 } 1543 1544 if (Ip6ModeData.AddressList != NULL) { 1545 FreePool (Ip6ModeData.AddressList); 1546 } 1547 if (Ip6ModeData.GroupTable != NULL) { 1548 FreePool (Ip6ModeData.GroupTable); 1549 } 1550 if (Ip6ModeData.RouteTable != NULL) { 1551 FreePool (Ip6ModeData.RouteTable); 1552 } 1553 if (Ip6ModeData.NeighborCache != NULL) { 1554 FreePool (Ip6ModeData.NeighborCache); 1555 } 1556 if (Ip6ModeData.PrefixTable != NULL) { 1557 FreePool (Ip6ModeData.PrefixTable); 1558 } 1559 if (Ip6ModeData.IcmpTypeList != NULL) { 1560 FreePool (Ip6ModeData.IcmpTypeList); 1561 } 1562 1563 if (GatewayIsFound || RetryCount == TimeOutInSecond) { 1564 break; 1565 } 1566 1567 RetryCount++; 1568 1569 // 1570 // Delay 1 second then recheck it again. 1571 // 1572 if (TimeOutEvt == NULL) { 1573 Status = gBS->CreateEvent ( 1574 EVT_TIMER, 1575 TPL_CALLBACK, 1576 NULL, 1577 NULL, 1578 &TimeOutEvt 1579 ); 1580 if (EFI_ERROR (Status)) { 1581 goto ON_EXIT; 1582 } 1583 } 1584 1585 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND); 1586 if (EFI_ERROR (Status)) { 1587 goto ON_EXIT; 1588 } 1589 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { 1590 Ip6->Poll (Ip6); 1591 } 1592 } 1593 1594 ON_EXIT: 1595 if (TimeOutEvt != NULL) { 1596 gBS->CloseEvent (TimeOutEvt); 1597 } 1598 1599 if (GatewayIsFound) { 1600 Status = EFI_SUCCESS; 1601 } else if (RetryCount == TimeOutInSecond) { 1602 Status = EFI_TIMEOUT; 1603 } 1604 1605 return Status; 1606 } 1607 1608 /** 1609 Register the ready station address and gateway by Ip6Config protocol. 1610 1611 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1612 @param[in] Address The pointer to the ready address. 1613 1614 @retval EFI_SUCCESS Registered the address succesfully. 1615 @retval Others Failed to register the address. 1616 1617 **/ 1618 EFI_STATUS 1619 PxeBcRegisterIp6Address ( 1620 IN PXEBC_PRIVATE_DATA *Private, 1621 IN EFI_IPv6_ADDRESS *Address 1622 ) 1623 { 1624 EFI_IP6_PROTOCOL *Ip6; 1625 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; 1626 EFI_IP6_CONFIG_POLICY Policy; 1627 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; 1628 EFI_IPv6_ADDRESS GatewayAddr; 1629 UINTN DataSize; 1630 EFI_EVENT MappedEvt; 1631 EFI_STATUS Status; 1632 BOOLEAN NoGateway; 1633 EFI_IPv6_ADDRESS *Ip6Addr; 1634 UINTN Index; 1635 1636 Status = EFI_SUCCESS; 1637 MappedEvt = NULL; 1638 Ip6Addr = NULL; 1639 DataSize = sizeof (EFI_IP6_CONFIG_POLICY); 1640 Ip6Cfg = Private->Ip6Cfg; 1641 Ip6 = Private->Ip6; 1642 NoGateway = FALSE; 1643 1644 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); 1645 CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS)); 1646 1647 Status = Ip6->Configure (Ip6, &Private->Ip6CfgData); 1648 if (EFI_ERROR (Status)) { 1649 goto ON_EXIT; 1650 } 1651 1652 // 1653 // Retrieve the gateway address from IP6 route table. 1654 // 1655 Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr); 1656 if (EFI_ERROR (Status)) { 1657 NoGateway = TRUE; 1658 } 1659 1660 // 1661 // There is no channel between IP6 and PXE driver about address setting, 1662 // so it has to set the new address by Ip6ConfigProtocol manually. 1663 // 1664 Policy = Ip6ConfigPolicyManual; 1665 Status = Ip6Cfg->SetData ( 1666 Ip6Cfg, 1667 Ip6ConfigDataTypePolicy, 1668 sizeof(EFI_IP6_CONFIG_POLICY), 1669 &Policy 1670 ); 1671 if (EFI_ERROR (Status)) { 1672 // 1673 // There is no need to recover later. 1674 // 1675 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX; 1676 goto ON_EXIT; 1677 } 1678 1679 // 1680 // Create a notify event to set address flag when DAD if IP6 driver succeeded. 1681 // 1682 Status = gBS->CreateEvent ( 1683 EVT_NOTIFY_SIGNAL, 1684 TPL_NOTIFY, 1685 PxeBcCommonNotify, 1686 &Private->IsAddressOk, 1687 &MappedEvt 1688 ); 1689 if (EFI_ERROR (Status)) { 1690 goto ON_EXIT; 1691 } 1692 1693 Private->IsAddressOk = FALSE; 1694 Status = Ip6Cfg->RegisterDataNotify ( 1695 Ip6Cfg, 1696 Ip6ConfigDataTypeManualAddress, 1697 MappedEvt 1698 ); 1699 if (EFI_ERROR(Status)) { 1700 goto ON_EXIT; 1701 } 1702 1703 Status = Ip6Cfg->SetData ( 1704 Ip6Cfg, 1705 Ip6ConfigDataTypeManualAddress, 1706 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS), 1707 &CfgAddr 1708 ); 1709 if (EFI_ERROR(Status) && Status != EFI_NOT_READY) { 1710 goto ON_EXIT; 1711 } else if (Status == EFI_NOT_READY) { 1712 // 1713 // Poll the network until the asynchronous process is finished. 1714 // 1715 while (!Private->IsAddressOk) { 1716 Ip6->Poll (Ip6); 1717 } 1718 // 1719 // Check whether the IP6 address setting is successed. 1720 // 1721 DataSize = 0; 1722 Status = Ip6Cfg->GetData ( 1723 Ip6Cfg, 1724 Ip6ConfigDataTypeManualAddress, 1725 &DataSize, 1726 NULL 1727 ); 1728 if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) { 1729 Status = EFI_DEVICE_ERROR; 1730 goto ON_EXIT; 1731 } 1732 1733 Ip6Addr = AllocatePool (DataSize); 1734 if (Ip6Addr == NULL) { 1735 return EFI_OUT_OF_RESOURCES; 1736 } 1737 Status = Ip6Cfg->GetData ( 1738 Ip6Cfg, 1739 Ip6ConfigDataTypeManualAddress, 1740 &DataSize, 1741 (VOID*) Ip6Addr 1742 ); 1743 if (EFI_ERROR (Status)) { 1744 Status = EFI_DEVICE_ERROR; 1745 goto ON_EXIT; 1746 } 1747 1748 for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) { 1749 if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) { 1750 break; 1751 } 1752 } 1753 if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { 1754 Status = EFI_ABORTED; 1755 goto ON_EXIT; 1756 } 1757 } 1758 1759 // 1760 // Set the default gateway address back if needed. 1761 // 1762 if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) { 1763 Status = Ip6Cfg->SetData ( 1764 Ip6Cfg, 1765 Ip6ConfigDataTypeGateway, 1766 sizeof (EFI_IPv6_ADDRESS), 1767 &GatewayAddr 1768 ); 1769 if (EFI_ERROR (Status)) { 1770 goto ON_EXIT; 1771 } 1772 } 1773 1774 ON_EXIT: 1775 if (MappedEvt != NULL) { 1776 Ip6Cfg->UnregisterDataNotify ( 1777 Ip6Cfg, 1778 Ip6ConfigDataTypeManualAddress, 1779 MappedEvt 1780 ); 1781 gBS->CloseEvent (MappedEvt); 1782 } 1783 if (Ip6Addr != NULL) { 1784 FreePool (Ip6Addr); 1785 } 1786 return Status; 1787 } 1788 1789 /** 1790 Set the IP6 policy to Automatic. 1791 1792 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1793 1794 @retval EFI_SUCCESS Switch the IP policy succesfully. 1795 @retval Others Unexpect error happened. 1796 1797 **/ 1798 EFI_STATUS 1799 PxeBcSetIp6Policy ( 1800 IN PXEBC_PRIVATE_DATA *Private 1801 ) 1802 { 1803 EFI_IP6_CONFIG_POLICY Policy; 1804 EFI_STATUS Status; 1805 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; 1806 UINTN DataSize; 1807 1808 Ip6Cfg = Private->Ip6Cfg; 1809 DataSize = sizeof (EFI_IP6_CONFIG_POLICY); 1810 1811 // 1812 // Get and store the current policy of IP6 driver. 1813 // 1814 Status = Ip6Cfg->GetData ( 1815 Ip6Cfg, 1816 Ip6ConfigDataTypePolicy, 1817 &DataSize, 1818 &Private->Ip6Policy 1819 ); 1820 if (EFI_ERROR (Status)) { 1821 return Status; 1822 } 1823 1824 if (Private->Ip6Policy == Ip6ConfigPolicyManual) { 1825 Policy = Ip6ConfigPolicyAutomatic; 1826 Status = Ip6Cfg->SetData ( 1827 Ip6Cfg, 1828 Ip6ConfigDataTypePolicy, 1829 sizeof(EFI_IP6_CONFIG_POLICY), 1830 &Policy 1831 ); 1832 if (EFI_ERROR (Status)) { 1833 // 1834 // There is no need to recover later. 1835 // 1836 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX; 1837 } 1838 } 1839 1840 return Status; 1841 } 1842 1843 /** 1844 This function will register the station IP address and flush IP instance to start using the new IP address. 1845 1846 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1847 1848 @retval EFI_SUCCESS The new IP address has been configured successfully. 1849 @retval Others Failed to configure the address. 1850 1851 **/ 1852 EFI_STATUS 1853 PxeBcSetIp6Address ( 1854 IN PXEBC_PRIVATE_DATA *Private 1855 ) 1856 { 1857 EFI_STATUS Status; 1858 EFI_DHCP6_PROTOCOL *Dhcp6; 1859 1860 Dhcp6 = Private->Dhcp6; 1861 1862 CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS)); 1863 CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS)); 1864 1865 Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6); 1866 if (EFI_ERROR (Status)) { 1867 Dhcp6->Stop (Dhcp6); 1868 return Status; 1869 } 1870 1871 Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL); 1872 if (EFI_ERROR (Status)) { 1873 PxeBcUnregisterIp6Address (Private); 1874 Dhcp6->Stop (Dhcp6); 1875 return Status; 1876 } 1877 1878 AsciiPrint ("\n Station IP address is "); 1879 PxeBcShowIp6Addr (&Private->StationIp.v6); 1880 1881 return EFI_SUCCESS; 1882 } 1883 1884 /** 1885 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver 1886 to intercept events that occurred in the configuration process. 1887 1888 @param[in] This The pointer to the EFI DHCPv6 Protocol. 1889 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure(). 1890 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver. 1891 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a 1892 state transition. 1893 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received. 1894 @param[out] NewPacket The packet that is used to replace the Packet above. 1895 1896 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process. 1897 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol 1898 driver will continue to wait for more packets. 1899 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process. 1900 1901 **/ 1902 EFI_STATUS 1903 EFIAPI 1904 PxeBcDhcp6CallBack ( 1905 IN EFI_DHCP6_PROTOCOL *This, 1906 IN VOID *Context, 1907 IN EFI_DHCP6_STATE CurrentState, 1908 IN EFI_DHCP6_EVENT Dhcp6Event, 1909 IN EFI_DHCP6_PACKET *Packet, 1910 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL 1911 ) 1912 { 1913 PXEBC_PRIVATE_DATA *Private; 1914 EFI_PXE_BASE_CODE_MODE *Mode; 1915 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; 1916 EFI_DHCP6_PACKET *SelectAd; 1917 EFI_STATUS Status; 1918 BOOLEAN Received; 1919 1920 if ((Dhcp6Event != Dhcp6RcvdAdvertise) && 1921 (Dhcp6Event != Dhcp6SelectAdvertise) && 1922 (Dhcp6Event != Dhcp6SendSolicit) && 1923 (Dhcp6Event != Dhcp6SendRequest) && 1924 (Dhcp6Event != Dhcp6RcvdReply)) { 1925 return EFI_SUCCESS; 1926 } 1927 1928 ASSERT (Packet != NULL); 1929 1930 Private = (PXEBC_PRIVATE_DATA *) Context; 1931 Mode = Private->PxeBc.Mode; 1932 Callback = Private->PxeBcCallback; 1933 1934 // 1935 // Callback to user when any traffic ocurred if has. 1936 // 1937 if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) { 1938 Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply); 1939 Status = Callback->Callback ( 1940 Callback, 1941 Private->Function, 1942 Received, 1943 Packet->Length, 1944 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6 1945 ); 1946 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { 1947 return EFI_ABORTED; 1948 } 1949 } 1950 1951 Status = EFI_SUCCESS; 1952 1953 switch (Dhcp6Event) { 1954 1955 case Dhcp6SendSolicit: 1956 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { 1957 // 1958 // If the to be sent packet exceeds the maximum length, abort the DHCP process. 1959 // 1960 Status = EFI_ABORTED; 1961 break; 1962 } 1963 1964 // 1965 // Record the first Solicate msg time 1966 // 1967 if (Private->SolicitTimes == 0) { 1968 CalcElapsedTime (Private); 1969 Private->SolicitTimes++; 1970 } 1971 // 1972 // Cache the dhcp discover packet to mode data directly. 1973 // 1974 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length); 1975 break; 1976 1977 case Dhcp6RcvdAdvertise: 1978 Status = EFI_NOT_READY; 1979 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { 1980 // 1981 // Ignore the incoming packets which exceed the maximum length. 1982 // 1983 break; 1984 } 1985 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { 1986 // 1987 // Cache the dhcp offers to OfferBuffer[] for select later, and record 1988 // the OfferIndex and OfferCount. 1989 // 1990 PxeBcCacheDhcp6Offer (Private, Packet); 1991 } 1992 break; 1993 1994 case Dhcp6SendRequest: 1995 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { 1996 // 1997 // If the to be sent packet exceeds the maximum length, abort the DHCP process. 1998 // 1999 Status = EFI_ABORTED; 2000 break; 2001 } 2002 2003 // 2004 // Store the request packet as seed packet for discover. 2005 // 2006 if (Private->Dhcp6Request != NULL) { 2007 FreePool (Private->Dhcp6Request); 2008 } 2009 Private->Dhcp6Request = AllocateZeroPool (Packet->Size); 2010 if (Private->Dhcp6Request != NULL) { 2011 CopyMem (Private->Dhcp6Request, Packet, Packet->Size); 2012 } 2013 break; 2014 2015 case Dhcp6SelectAdvertise: 2016 // 2017 // Select offer by the default policy or by order, and record the SelectIndex 2018 // and SelectProxyType. 2019 // 2020 PxeBcSelectDhcp6Offer (Private); 2021 2022 if (Private->SelectIndex == 0) { 2023 Status = EFI_ABORTED; 2024 } else { 2025 ASSERT (NewPacket != NULL); 2026 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer; 2027 *NewPacket = AllocateZeroPool (SelectAd->Size); 2028 ASSERT (*NewPacket != NULL); 2029 CopyMem (*NewPacket, SelectAd, SelectAd->Size); 2030 } 2031 break; 2032 2033 case Dhcp6RcvdReply: 2034 // 2035 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data 2036 // without verification. 2037 // 2038 ASSERT (Private->SelectIndex != 0); 2039 Status = PxeBcCopyDhcp6Ack (Private, Packet, FALSE); 2040 if (EFI_ERROR (Status)) { 2041 Status = EFI_ABORTED; 2042 } 2043 break; 2044 2045 default: 2046 ASSERT (0); 2047 } 2048 2049 return Status; 2050 } 2051 2052 2053 /** 2054 Build and send out the request packet for the bootfile, and parse the reply. 2055 2056 @param[in] Private The pointer to PxeBc private data. 2057 @param[in] Type PxeBc option boot item type. 2058 @param[in] Layer The pointer to option boot item layer. 2059 @param[in] UseBis Use BIS or not. 2060 @param[in] DestIp The pointer to the server address. 2061 2062 @retval EFI_SUCCESS Successfully discovered the boot file. 2063 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. 2064 @retval EFI_NOT_FOUND Can't get the PXE reply packet. 2065 @retval Others Failed to discover the boot file. 2066 2067 **/ 2068 EFI_STATUS 2069 PxeBcDhcp6Discover ( 2070 IN PXEBC_PRIVATE_DATA *Private, 2071 IN UINT16 Type, 2072 IN UINT16 *Layer, 2073 IN BOOLEAN UseBis, 2074 IN EFI_IP_ADDRESS *DestIp 2075 ) 2076 { 2077 EFI_PXE_BASE_CODE_UDP_PORT SrcPort; 2078 EFI_PXE_BASE_CODE_UDP_PORT DestPort; 2079 EFI_PXE_BASE_CODE_MODE *Mode; 2080 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; 2081 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; 2082 UINTN DiscoverLen; 2083 EFI_DHCP6_PACKET *Request; 2084 UINTN RequestLen; 2085 EFI_DHCP6_PACKET *Reply; 2086 UINT8 *RequestOpt; 2087 UINT8 *DiscoverOpt; 2088 UINTN ReadSize; 2089 UINT16 OpCode; 2090 UINT16 OpLen; 2091 UINT32 Xid; 2092 EFI_STATUS Status; 2093 2094 PxeBc = &Private->PxeBc; 2095 Mode = PxeBc->Mode; 2096 Request = Private->Dhcp6Request; 2097 SrcPort = PXEBC_BS_DISCOVER_PORT; 2098 DestPort = PXEBC_BS_DISCOVER_PORT; 2099 2100 if (!UseBis && Layer != NULL) { 2101 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; 2102 } 2103 2104 if (Request == NULL) { 2105 return EFI_DEVICE_ERROR; 2106 } 2107 2108 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); 2109 if (Discover == NULL) { 2110 return EFI_OUT_OF_RESOURCES; 2111 } 2112 2113 // 2114 // Build the discover packet by the cached request packet before. 2115 // 2116 Xid = NET_RANDOM (NetRandomInitSeed ()); 2117 Discover->TransactionId = HTONL (Xid); 2118 Discover->MessageType = Request->Dhcp6.Header.MessageType; 2119 RequestOpt = Request->Dhcp6.Option; 2120 DiscoverOpt = Discover->DhcpOptions; 2121 DiscoverLen = sizeof (EFI_DHCP6_HEADER); 2122 RequestLen = DiscoverLen; 2123 2124 while (RequestLen < Request->Length) { 2125 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); 2126 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); 2127 if (OpCode != EFI_DHCP6_IA_TYPE_NA && 2128 OpCode != EFI_DHCP6_IA_TYPE_TA) { 2129 // 2130 // Copy all the options except IA option. 2131 // 2132 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); 2133 DiscoverOpt += (OpLen + 4); 2134 DiscoverLen += (OpLen + 4); 2135 } 2136 RequestOpt += (OpLen + 4); 2137 RequestLen += (OpLen + 4); 2138 } 2139 2140 Status = PxeBc->UdpWrite ( 2141 PxeBc, 2142 0, 2143 &Private->ServerIp, 2144 &DestPort, 2145 NULL, 2146 &Private->StationIp, 2147 &SrcPort, 2148 NULL, 2149 NULL, 2150 &DiscoverLen, 2151 (VOID *) Discover 2152 ); 2153 if (EFI_ERROR (Status)) { 2154 return Status; 2155 } 2156 2157 // 2158 // Cache the right PXE reply packet here, set valid flag later. 2159 // Especially for PXE discover packet, store it into mode data here. 2160 // 2161 if (Private->IsDoDiscover) { 2162 CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen); 2163 Reply = &Private->PxeReply.Dhcp6.Packet.Ack; 2164 } else { 2165 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; 2166 } 2167 ReadSize = (UINTN) Reply->Size; 2168 2169 // 2170 // Start Udp6Read instance 2171 // 2172 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); 2173 if (EFI_ERROR (Status)) { 2174 return Status; 2175 } 2176 2177 Status = PxeBc->UdpRead ( 2178 PxeBc, 2179 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, 2180 NULL, 2181 &SrcPort, 2182 &Private->ServerIp, 2183 &DestPort, 2184 NULL, 2185 NULL, 2186 &ReadSize, 2187 (VOID *) &Reply->Dhcp6 2188 ); 2189 // 2190 // Stop Udp6Read instance 2191 // 2192 Private->Udp6Read->Configure (Private->Udp6Read, NULL); 2193 if (EFI_ERROR (Status)) { 2194 return Status; 2195 } 2196 2197 return EFI_SUCCESS; 2198 } 2199 2200 2201 /** 2202 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information. 2203 2204 @param[in] Private The pointer to PxeBc private data. 2205 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL 2206 2207 @retval EFI_SUCCESS The S.A.R.R. process successfully finished. 2208 @retval Others Failed to finish the S.A.R.R. process. 2209 2210 **/ 2211 EFI_STATUS 2212 PxeBcDhcp6Sarr ( 2213 IN PXEBC_PRIVATE_DATA *Private, 2214 IN EFI_DHCP6_PROTOCOL *Dhcp6 2215 ) 2216 { 2217 EFI_PXE_BASE_CODE_MODE *PxeMode; 2218 EFI_DHCP6_CONFIG_DATA Config; 2219 EFI_DHCP6_MODE_DATA Mode; 2220 EFI_DHCP6_RETRANSMISSION *Retransmit; 2221 EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM]; 2222 UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE]; 2223 UINT32 OptCount; 2224 EFI_STATUS Status; 2225 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; 2226 EFI_STATUS TimerStatus; 2227 EFI_EVENT Timer; 2228 UINT64 GetMappingTimeOut; 2229 UINTN DataSize; 2230 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; 2231 2232 Status = EFI_SUCCESS; 2233 PxeMode = Private->PxeBc.Mode; 2234 Ip6Cfg = Private->Ip6Cfg; 2235 Timer = NULL; 2236 2237 // 2238 // Build option list for the request packet. 2239 // 2240 OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer); 2241 ASSERT (OptCount> 0); 2242 2243 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); 2244 if (Retransmit == NULL) { 2245 return EFI_OUT_OF_RESOURCES; 2246 } 2247 2248 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); 2249 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); 2250 2251 Config.OptionCount = OptCount; 2252 Config.OptionList = OptList; 2253 Config.Dhcp6Callback = PxeBcDhcp6CallBack; 2254 Config.CallbackContext = Private; 2255 Config.IaInfoEvent = NULL; 2256 Config.RapidCommit = FALSE; 2257 Config.ReconfigureAccept = FALSE; 2258 Config.IaDescriptor.IaId = Private->IaId; 2259 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; 2260 Config.SolicitRetransmission = Retransmit; 2261 Retransmit->Irt = 4; 2262 Retransmit->Mrc = 4; 2263 Retransmit->Mrt = 32; 2264 Retransmit->Mrd = 60; 2265 2266 // 2267 // Configure the DHCPv6 instance for PXE boot. 2268 // 2269 Status = Dhcp6->Configure (Dhcp6, &Config); 2270 FreePool (Retransmit); 2271 if (EFI_ERROR (Status)) { 2272 return Status; 2273 } 2274 2275 // 2276 // Initialize the record fields for DHCPv6 offer in private data. 2277 // 2278 Private->IsProxyRecved = FALSE; 2279 Private->OfferNum = 0; 2280 Private->SelectIndex = 0; 2281 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 2282 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 2283 2284 2285 // 2286 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. 2287 // 2288 Status = Dhcp6->Start (Dhcp6); 2289 if (Status == EFI_NO_MAPPING) { 2290 // 2291 // IP6 Linklocal address is not available for use, so stop current Dhcp process 2292 // and wait for duplicate address detection to finish. 2293 // 2294 Dhcp6->Stop (Dhcp6); 2295 2296 // 2297 // Get Duplicate Address Detection Transmits count. 2298 // 2299 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); 2300 Status = Ip6Cfg->GetData ( 2301 Ip6Cfg, 2302 Ip6ConfigDataTypeDupAddrDetectTransmits, 2303 &DataSize, 2304 &DadXmits 2305 ); 2306 if (EFI_ERROR (Status)) { 2307 Dhcp6->Configure (Dhcp6, NULL); 2308 return Status; 2309 } 2310 2311 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer); 2312 if (EFI_ERROR (Status)) { 2313 Dhcp6->Configure (Dhcp6, NULL); 2314 return Status; 2315 } 2316 2317 GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY; 2318 Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut); 2319 if (EFI_ERROR (Status)) { 2320 gBS->CloseEvent (Timer); 2321 Dhcp6->Configure (Dhcp6, NULL); 2322 return Status; 2323 } 2324 2325 do { 2326 2327 TimerStatus = gBS->CheckEvent (Timer); 2328 if (!EFI_ERROR (TimerStatus)) { 2329 Status = Dhcp6->Start (Dhcp6); 2330 } 2331 } while (TimerStatus == EFI_NOT_READY); 2332 2333 gBS->CloseEvent (Timer); 2334 } 2335 if (EFI_ERROR (Status)) { 2336 if (Status == EFI_ICMP_ERROR) { 2337 PxeMode->IcmpErrorReceived = TRUE; 2338 } 2339 Dhcp6->Configure (Dhcp6, NULL); 2340 return Status; 2341 } 2342 2343 // 2344 // Get the acquired IPv6 address and store them. 2345 // 2346 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL); 2347 if (EFI_ERROR (Status)) { 2348 Dhcp6->Stop (Dhcp6); 2349 return Status; 2350 } 2351 2352 ASSERT ((Mode.Ia != NULL) && (Mode.Ia->State == Dhcp6Bound)); 2353 // 2354 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the 2355 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when 2356 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as 2357 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery 2358 // to find a valid router address. 2359 // 2360 CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS)); 2361 if (Mode.ClientId != NULL) { 2362 FreePool (Mode.ClientId); 2363 } 2364 if (Mode.Ia != NULL) { 2365 FreePool (Mode.Ia); 2366 } 2367 // 2368 // Check the selected offer whether BINL retry is needed. 2369 // 2370 Status = PxeBcHandleDhcp6Offer (Private); 2371 if (EFI_ERROR (Status)) { 2372 Dhcp6->Stop (Dhcp6); 2373 return Status; 2374 } 2375 2376 return EFI_SUCCESS; 2377 } 2378