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