1/** @file 2 Functions implementation related with DHCPv6 for HTTP boot driver. 3 4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials are licensed and made available under 6the terms and conditions of the BSD License that accompanies this distribution. 7The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php. 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "HttpBootDxe.h" 16 17/** 18 Build the options buffer for the DHCPv6 request packet. 19 20 @param[in] Private The pointer to HTTP BOOT driver private data. 21 @param[out] OptList The pointer to the option pointer array. 22 @param[in] Buffer The pointer to the buffer to contain the option list. 23 24 @return Index The count of the built-in options. 25 26**/ 27UINT32 28HttpBootBuildDhcp6Options ( 29 IN HTTP_BOOT_PRIVATE_DATA *Private, 30 OUT EFI_DHCP6_PACKET_OPTION **OptList, 31 IN UINT8 *Buffer 32 ) 33{ 34 HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt; 35 UINT16 Value; 36 UINT32 Index; 37 38 Index = 0; 39 OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer; 40 41 // 42 // Append client option request option 43 // 44 OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_ORO); 45 OptList[Index]->OpLen = HTONS (8); 46 OptEnt.Oro = (HTTP_BOOT_DHCP6_OPTION_ORO *) OptList[Index]->Data; 47 OptEnt.Oro->OpCode[0] = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL); 48 OptEnt.Oro->OpCode[1] = HTONS(HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM); 49 OptEnt.Oro->OpCode[2] = HTONS(HTTP_BOOT_DHCP6_OPT_DNS_SERVERS); 50 OptEnt.Oro->OpCode[3] = HTONS(HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS); 51 Index++; 52 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 53 54 // 55 // Append client network device interface option 56 // 57 OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_UNDI); 58 OptList[Index]->OpLen = HTONS ((UINT16)3); 59 OptEnt.Undi = (HTTP_BOOT_DHCP6_OPTION_UNDI *) OptList[Index]->Data; 60 61 if (Private->Nii != NULL) { 62 OptEnt.Undi->Type = Private->Nii->Type; 63 OptEnt.Undi->MajorVer = Private->Nii->MajorVer; 64 OptEnt.Undi->MinorVer = Private->Nii->MinorVer; 65 } else { 66 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; 67 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; 68 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; 69 } 70 71 Index++; 72 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 73 74 // 75 // Append client system architecture option 76 // 77 OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_ARCH); 78 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH)); 79 OptEnt.Arch = (HTTP_BOOT_DHCP6_OPTION_ARCH *) OptList[Index]->Data; 80 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE); 81 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); 82 Index++; 83 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); 84 85 // 86 // Append vendor class identify option. 87 // 88 OptList[Index]->OpCode = HTONS (HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS); 89 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS)); 90 OptEnt.VendorClass = (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data; 91 OptEnt.VendorClass->Vendor = HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM); 92 OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (HTTP_BOOT_CLASS_ID)); 93 CopyMem ( 94 &OptEnt.VendorClass->ClassId, 95 DEFAULT_CLASS_ID_DATA, 96 sizeof (HTTP_BOOT_CLASS_ID) 97 ); 98 HttpBootUintnToAscDecWithFormat ( 99 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE, 100 OptEnt.VendorClass->ClassId.ArchitectureType, 101 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType) 102 ); 103 104 if (Private->Nii != NULL) { 105 CopyMem ( 106 OptEnt.VendorClass->ClassId.InterfaceName, 107 Private->Nii->StringId, 108 sizeof (OptEnt.VendorClass->ClassId.InterfaceName) 109 ); 110 HttpBootUintnToAscDecWithFormat ( 111 Private->Nii->MajorVer, 112 OptEnt.VendorClass->ClassId.UndiMajor, 113 sizeof (OptEnt.VendorClass->ClassId.UndiMajor) 114 ); 115 HttpBootUintnToAscDecWithFormat ( 116 Private->Nii->MinorVer, 117 OptEnt.VendorClass->ClassId.UndiMinor, 118 sizeof (OptEnt.VendorClass->ClassId.UndiMinor) 119 ); 120 } 121 122 Index++; 123 124 return Index; 125} 126 127/** 128 Parse out a DHCPv6 option by OptTag, and find the position in buffer. 129 130 @param[in] Buffer The pointer to the option buffer. 131 @param[in] Length Length of the option buffer. 132 @param[in] OptTag The required option tag. 133 134 @retval NULL Failed to parse the required option. 135 @retval Others The postion of the required option in buffer. 136 137**/ 138EFI_DHCP6_PACKET_OPTION * 139HttpBootParseDhcp6Options ( 140 IN UINT8 *Buffer, 141 IN UINT32 Length, 142 IN UINT16 OptTag 143 ) 144{ 145 EFI_DHCP6_PACKET_OPTION *Option; 146 UINT32 Offset; 147 148 Option = (EFI_DHCP6_PACKET_OPTION *) Buffer; 149 Offset = 0; 150 151 // 152 // OpLen and OpCode here are both stored in network order. 153 // 154 while (Offset < Length) { 155 156 if (NTOHS (Option->OpCode) == OptTag) { 157 158 return Option; 159 } 160 161 Offset += (NTOHS(Option->OpLen) + 4); 162 Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset); 163 } 164 165 return NULL; 166 167} 168 169/** 170 Parse the cached DHCPv6 packet, including all the options. 171 172 @param[in] Cache6 The pointer to a cached DHCPv6 packet. 173 174 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully. 175 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet. 176 177**/ 178EFI_STATUS 179HttpBootParseDhcp6Packet ( 180 IN HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6 181 ) 182{ 183 EFI_DHCP6_PACKET *Offer; 184 EFI_DHCP6_PACKET_OPTION **Options; 185 EFI_DHCP6_PACKET_OPTION *Option; 186 HTTP_BOOT_OFFER_TYPE OfferType; 187 EFI_IPv6_ADDRESS IpAddr; 188 BOOLEAN IsProxyOffer; 189 BOOLEAN IsHttpOffer; 190 BOOLEAN IsDnsOffer; 191 BOOLEAN IpExpressedUri; 192 EFI_STATUS Status; 193 UINT32 Offset; 194 UINT32 Length; 195 196 IsDnsOffer = FALSE; 197 IpExpressedUri = FALSE; 198 IsProxyOffer = TRUE; 199 IsHttpOffer = FALSE; 200 Offer = &Cache6->Packet.Offer; 201 Options = Cache6->OptList; 202 203 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList)); 204 205 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option); 206 Offset = 0; 207 Length = GET_DHCP6_OPTION_SIZE (Offer); 208 209 // 210 // OpLen and OpCode here are both stored in network order, since they are from original packet. 211 // 212 while (Offset < Length) { 213 214 if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_IA_NA) { 215 Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option; 216 } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_URL) { 217 // 218 // The server sends this option to inform the client about an URL to a boot file. 219 // 220 Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] = Option; 221 } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_BOOT_FILE_PARAM) { 222 Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option; 223 } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_VENDOR_CLASS) { 224 Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option; 225 } else if (NTOHS (Option->OpCode) == HTTP_BOOT_DHCP6_OPT_DNS_SERVERS) { 226 Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER] = Option; 227 } 228 229 Offset += (NTOHS (Option->OpLen) + 4); 230 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); 231 } 232 // 233 // The offer with assigned client address is NOT a proxy offer. 234 // An ia_na option, embeded with valid ia_addr option and a status_code of success. 235 // 236 Option = Options[HTTP_BOOT_DHCP6_IDX_IA_NA]; 237 if (Option != NULL) { 238 Option = HttpBootParseDhcp6Options ( 239 Option->Data + 12, 240 NTOHS (Option->OpLen), 241 HTTP_BOOT_DHCP6_OPT_STATUS_CODE 242 ); 243 if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { 244 IsProxyOffer = FALSE; 245 } 246 } 247 248 // 249 // The offer with "HTTPClient" is a Http offer. 250 // 251 Option = Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS]; 252 253 if (Option != NULL && 254 NTOHS(Option->OpLen) >= 10 && 255 CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 0) { 256 IsHttpOffer = TRUE; 257 } 258 259 // 260 // The offer with Domain Server is a DNS offer. 261 // 262 Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER]; 263 if (Option != NULL) { 264 IsDnsOffer = TRUE; 265 } 266 267 // 268 // Http offer must have a boot URI. 269 // 270 if (IsHttpOffer && Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL) { 271 return EFI_DEVICE_ERROR; 272 } 273 274 // 275 // Try to retrieve the IP of HTTP server from URI. 276 // 277 if (IsHttpOffer) { 278 Status = HttpParseUrl ( 279 (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, 280 (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data), 281 FALSE, 282 &Cache6->UriParser 283 ); 284 if (EFI_ERROR (Status)) { 285 return EFI_DEVICE_ERROR; 286 } 287 288 Status = HttpUrlGetIp6 ( 289 (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data, 290 Cache6->UriParser, 291 &IpAddr 292 ); 293 IpExpressedUri = !EFI_ERROR (Status); 294 } 295 296 // 297 // Determine offer type of the DHCPv6 packet. 298 // 299 if (IsHttpOffer) { 300 if (IpExpressedUri) { 301 OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri; 302 } else { 303 if (!IsProxyOffer) { 304 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri; 305 } else { 306 OfferType = HttpOfferTypeProxyNameUri; 307 } 308 } 309 310 } else { 311 if (!IsProxyOffer) { 312 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly; 313 } else { 314 return EFI_DEVICE_ERROR; 315 } 316 } 317 318 Cache6->OfferType = OfferType; 319 return EFI_SUCCESS; 320} 321 322/** 323 Cache the DHCPv6 packet. 324 325 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet. 326 @param[in] Src The pointer to the DHCPv6 packet to be cached. 327 328**/ 329VOID 330HttpBootCacheDhcp6Packet ( 331 IN EFI_DHCP6_PACKET *Dst, 332 IN EFI_DHCP6_PACKET *Src 333 ) 334{ 335 ASSERT (Dst->Size >= Src->Length); 336 337 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length); 338 Dst->Length = Src->Length; 339} 340 341/** 342 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount. 343 344 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 345 @param[in] RcvdOffer The pointer to the received offer packet. 346 347**/ 348VOID 349HttpBootCacheDhcp6Offer ( 350 IN HTTP_BOOT_PRIVATE_DATA *Private, 351 IN EFI_DHCP6_PACKET *RcvdOffer 352 ) 353{ 354 HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6; 355 EFI_DHCP6_PACKET *Offer; 356 HTTP_BOOT_OFFER_TYPE OfferType; 357 358 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6; 359 Offer = &Cache6->Packet.Offer; 360 361 // 362 // Cache the content of DHCPv6 packet firstly. 363 // 364 HttpBootCacheDhcp6Packet(Offer, RcvdOffer); 365 366 // 367 // Validate the DHCPv6 packet, and parse the options and offer type. 368 // 369 if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) { 370 return ; 371 } 372 373 // 374 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. 375 // 376 OfferType = Cache6->OfferType; 377 ASSERT (OfferType < HttpOfferTypeMax); 378 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM); 379 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 380 Private->OfferCount[OfferType]++; 381 Private->OfferNum++; 382} 383 384/** 385 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver 386 to intercept events that occurred in the configuration process. 387 388 @param[in] This The pointer to the EFI DHCPv6 Protocol. 389 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure(). 390 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver. 391 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a 392 state transition. 393 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received. 394 @param[out] NewPacket The packet that is used to replace the Packet above. 395 396 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process. 397 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol 398 driver will continue to wait for more packets. 399 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process. 400 401**/ 402EFI_STATUS 403EFIAPI 404HttpBootDhcp6CallBack ( 405 IN EFI_DHCP6_PROTOCOL *This, 406 IN VOID *Context, 407 IN EFI_DHCP6_STATE CurrentState, 408 IN EFI_DHCP6_EVENT Dhcp6Event, 409 IN EFI_DHCP6_PACKET *Packet, 410 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL 411 ) 412{ 413 HTTP_BOOT_PRIVATE_DATA *Private; 414 EFI_DHCP6_PACKET *SelectAd; 415 EFI_STATUS Status; 416 if ((Dhcp6Event != Dhcp6RcvdAdvertise) && (Dhcp6Event != Dhcp6SelectAdvertise)) { 417 return EFI_SUCCESS; 418 } 419 420 ASSERT (Packet != NULL); 421 422 Private = (HTTP_BOOT_PRIVATE_DATA *) Context; 423 Status = EFI_SUCCESS; 424 switch (Dhcp6Event) { 425 426 case Dhcp6RcvdAdvertise: 427 Status = EFI_NOT_READY; 428 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) { 429 // 430 // Cache the dhcp offers to OfferBuffer[] for select later, and record 431 // the OfferIndex and OfferCount. 432 // 433 HttpBootCacheDhcp6Offer (Private, Packet); 434 } 435 break; 436 437 case Dhcp6SelectAdvertise: 438 // 439 // Select offer by the default policy or by order, and record the SelectIndex 440 // and SelectProxyType. 441 // 442 HttpBootSelectDhcpOffer (Private); 443 444 if (Private->SelectIndex == 0) { 445 Status = EFI_ABORTED; 446 } else { 447 ASSERT (NewPacket != NULL); 448 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer; 449 *NewPacket = AllocateZeroPool (SelectAd->Size); 450 ASSERT (*NewPacket != NULL); 451 CopyMem (*NewPacket, SelectAd, SelectAd->Size); 452 } 453 break; 454 455 default: 456 break; 457 } 458 459 return Status; 460} 461 462/** 463 Check whether IP driver could route the message which will be sent to ServerIp address. 464 465 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid 466 route is found in IP6 route table, the address will be filed in GatewayAddr and return. 467 468 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 469 @param[in] TimeOutInSecond Timeout value in seconds. 470 @param[out] GatewayAddr Pointer to store the gateway IP address. 471 472 @retval EFI_SUCCESS Found a valid gateway address successfully. 473 @retval EFI_TIMEOUT The operation is time out. 474 @retval Other Unexpect error happened. 475 476**/ 477EFI_STATUS 478HttpBootCheckRouteTable ( 479 IN HTTP_BOOT_PRIVATE_DATA *Private, 480 IN UINTN TimeOutInSecond, 481 OUT EFI_IPv6_ADDRESS *GatewayAddr 482 ) 483{ 484 EFI_STATUS Status; 485 EFI_IP6_PROTOCOL *Ip6; 486 EFI_IP6_MODE_DATA Ip6ModeData; 487 UINTN Index; 488 EFI_EVENT TimeOutEvt; 489 UINTN RetryCount; 490 BOOLEAN GatewayIsFound; 491 492 ASSERT (GatewayAddr != NULL); 493 ASSERT (Private != NULL); 494 495 Ip6 = Private->Ip6; 496 GatewayIsFound = FALSE; 497 RetryCount = 0; 498 TimeOutEvt = NULL; 499 Status = EFI_SUCCESS; 500 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS)); 501 502 while (TRUE) { 503 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL); 504 if (EFI_ERROR (Status)) { 505 goto ON_EXIT; 506 } 507 508 // 509 // Find out the gateway address which can route the message which send to ServerIp. 510 // 511 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) { 512 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) { 513 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway); 514 GatewayIsFound = TRUE; 515 break; 516 } 517 } 518 519 if (Ip6ModeData.AddressList != NULL) { 520 FreePool (Ip6ModeData.AddressList); 521 } 522 if (Ip6ModeData.GroupTable != NULL) { 523 FreePool (Ip6ModeData.GroupTable); 524 } 525 if (Ip6ModeData.RouteTable != NULL) { 526 FreePool (Ip6ModeData.RouteTable); 527 } 528 if (Ip6ModeData.NeighborCache != NULL) { 529 FreePool (Ip6ModeData.NeighborCache); 530 } 531 if (Ip6ModeData.PrefixTable != NULL) { 532 FreePool (Ip6ModeData.PrefixTable); 533 } 534 if (Ip6ModeData.IcmpTypeList != NULL) { 535 FreePool (Ip6ModeData.IcmpTypeList); 536 } 537 538 if (GatewayIsFound || RetryCount == TimeOutInSecond) { 539 break; 540 } 541 542 RetryCount++; 543 544 // 545 // Delay 1 second then recheck it again. 546 // 547 if (TimeOutEvt == NULL) { 548 Status = gBS->CreateEvent ( 549 EVT_TIMER, 550 TPL_CALLBACK, 551 NULL, 552 NULL, 553 &TimeOutEvt 554 ); 555 if (EFI_ERROR (Status)) { 556 goto ON_EXIT; 557 } 558 } 559 560 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND); 561 if (EFI_ERROR (Status)) { 562 goto ON_EXIT; 563 } 564 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { 565 Ip6->Poll (Ip6); 566 } 567 } 568 569ON_EXIT: 570 if (TimeOutEvt != NULL) { 571 gBS->CloseEvent (TimeOutEvt); 572 } 573 574 if (GatewayIsFound) { 575 Status = EFI_SUCCESS; 576 } else if (RetryCount == TimeOutInSecond) { 577 Status = EFI_TIMEOUT; 578 } 579 580 return Status; 581} 582 583/** 584 Set the IP6 policy to Automatic. 585 586 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 587 588 @retval EFI_SUCCESS Switch the IP policy succesfully. 589 @retval Others Unexpect error happened. 590 591**/ 592EFI_STATUS 593HttpBootSetIp6Policy ( 594 IN HTTP_BOOT_PRIVATE_DATA *Private 595 ) 596{ 597 EFI_IP6_CONFIG_POLICY Policy; 598 EFI_IP6_CONFIG_PROTOCOL *Ip6Config; 599 EFI_STATUS Status; 600 UINTN DataSize; 601 602 Ip6Config = Private->Ip6Config; 603 DataSize = sizeof (EFI_IP6_CONFIG_POLICY); 604 605 // 606 // Get and store the current policy of IP6 driver. 607 // 608 Status = Ip6Config->GetData ( 609 Ip6Config, 610 Ip6ConfigDataTypePolicy, 611 &DataSize, 612 &Policy 613 ); 614 if (EFI_ERROR (Status)) { 615 return Status; 616 } 617 618 if (Policy == Ip6ConfigPolicyManual) { 619 Policy = Ip6ConfigPolicyAutomatic; 620 Status = Ip6Config->SetData ( 621 Ip6Config, 622 Ip6ConfigDataTypePolicy, 623 sizeof(EFI_IP6_CONFIG_POLICY), 624 &Policy 625 ); 626 if (EFI_ERROR (Status)) { 627 return Status; 628 } 629 } 630 return EFI_SUCCESS; 631} 632 633/** 634 This function will register the default DNS addresses to the network device. 635 636 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 637 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes. 638 @param[in] DnsServerData Point a list of DNS server address in an array 639 of EFI_IPv6_ADDRESS instances. 640 641 @retval EFI_SUCCESS The DNS configuration has been configured successfully. 642 @retval Others Failed to configure the address. 643 644**/ 645EFI_STATUS 646HttpBootSetIp6Dns ( 647 IN HTTP_BOOT_PRIVATE_DATA *Private, 648 IN UINTN DataLength, 649 IN VOID *DnsServerData 650 ) 651{ 652 EFI_IP6_CONFIG_PROTOCOL *Ip6Config; 653 654 ASSERT (Private->UsingIpv6); 655 656 Ip6Config = Private->Ip6Config; 657 658 return Ip6Config->SetData ( 659 Ip6Config, 660 Ip6ConfigDataTypeDnsServer, 661 DataLength, 662 DnsServerData 663 ); 664} 665 666/** 667 This function will register the IPv6 gateway address to the network device. 668 669 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 670 671 @retval EFI_SUCCESS The new IP configuration has been configured successfully. 672 @retval Others Failed to configure the address. 673 674**/ 675EFI_STATUS 676HttpBootSetIp6Gateway ( 677 IN HTTP_BOOT_PRIVATE_DATA *Private 678 ) 679{ 680 EFI_IP6_CONFIG_PROTOCOL *Ip6Config; 681 EFI_STATUS Status; 682 683 ASSERT (Private->UsingIpv6); 684 Ip6Config = Private->Ip6Config; 685 686 // 687 // Set the default gateway address. 688 // 689 if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) { 690 Status = Ip6Config->SetData ( 691 Ip6Config, 692 Ip6ConfigDataTypeGateway, 693 sizeof (EFI_IPv6_ADDRESS), 694 &Private->GatewayIp.v6 695 ); 696 if (EFI_ERROR(Status)) { 697 return Status; 698 } 699 } 700 701 return EFI_SUCCESS; 702} 703 704/** 705 This function will register the station IP address. 706 707 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 708 709 @retval EFI_SUCCESS The new IP address has been configured successfully. 710 @retval Others Failed to configure the address. 711 712**/ 713EFI_STATUS 714HttpBootSetIp6Address ( 715 IN HTTP_BOOT_PRIVATE_DATA *Private 716) 717{ 718 EFI_STATUS Status; 719 EFI_IP6_PROTOCOL *Ip6; 720 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; 721 EFI_IP6_CONFIG_POLICY Policy; 722 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; 723 EFI_IPv6_ADDRESS *Ip6Addr; 724 EFI_IPv6_ADDRESS GatewayAddr; 725 EFI_IP6_CONFIG_DATA Ip6CfgData; 726 EFI_EVENT MappedEvt; 727 UINTN DataSize; 728 BOOLEAN IsAddressOk; 729 UINTN Index; 730 731 ASSERT (Private->UsingIpv6); 732 733 MappedEvt = NULL; 734 IsAddressOk = FALSE; 735 Ip6Addr = NULL; 736 Ip6Cfg = Private->Ip6Config; 737 Ip6 = Private->Ip6; 738 739 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); 740 CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS)); 741 ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA)); 742 743 Ip6CfgData.AcceptIcmpErrors = TRUE; 744 Ip6CfgData.DefaultProtocol = IP6_ICMP; 745 Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT; 746 Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME; 747 Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME; 748 749 Status = Ip6->Configure (Ip6, &Ip6CfgData); 750 if (EFI_ERROR (Status)) { 751 goto ON_EXIT; 752 } 753 754 // 755 // Retrieve the gateway address from IP6 route table. 756 // 757 Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr); 758 if (EFI_ERROR (Status)) { 759 Private->NoGateway = TRUE; 760 } else { 761 IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr); 762 } 763 764 // 765 // Set the new address by Ip6ConfigProtocol manually. 766 // 767 Policy = Ip6ConfigPolicyManual; 768 Status = Ip6Cfg->SetData ( 769 Ip6Cfg, 770 Ip6ConfigDataTypePolicy, 771 sizeof(EFI_IP6_CONFIG_POLICY), 772 &Policy 773 ); 774 if (EFI_ERROR (Status)) { 775 goto ON_EXIT; 776 } 777 778 // 779 // Create a notify event to set address flag when DAD if IP6 driver succeeded. 780 // 781 Status = gBS->CreateEvent ( 782 EVT_NOTIFY_SIGNAL, 783 TPL_NOTIFY, 784 HttpBootCommonNotify, 785 &IsAddressOk, 786 &MappedEvt 787 ); 788 if (EFI_ERROR (Status)) { 789 goto ON_EXIT; 790 } 791 792 // 793 // Set static host ip6 address. This is a asynchronous process. 794 // 795 Status = Ip6Cfg->RegisterDataNotify ( 796 Ip6Cfg, 797 Ip6ConfigDataTypeManualAddress, 798 MappedEvt 799 ); 800 if (EFI_ERROR(Status)) { 801 goto ON_EXIT; 802 } 803 804 Status = Ip6Cfg->SetData ( 805 Ip6Cfg, 806 Ip6ConfigDataTypeManualAddress, 807 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS), 808 &CfgAddr 809 ); 810 if (EFI_ERROR (Status) && Status != EFI_NOT_READY) { 811 goto ON_EXIT; 812 } else if (Status == EFI_NOT_READY) { 813 // 814 // Poll the network until the asynchronous process is finished. 815 // 816 while (!IsAddressOk) { 817 Ip6->Poll (Ip6); 818 } 819 // 820 // Check whether the Ip6 Address setting is successed. 821 // 822 DataSize = 0; 823 Status = Ip6Cfg->GetData ( 824 Ip6Cfg, 825 Ip6ConfigDataTypeManualAddress, 826 &DataSize, 827 NULL 828 ); 829 if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) { 830 Status = EFI_DEVICE_ERROR; 831 goto ON_EXIT; 832 } 833 834 Ip6Addr = AllocatePool (DataSize); 835 if (Ip6Addr == NULL) { 836 return EFI_OUT_OF_RESOURCES; 837 } 838 Status = Ip6Cfg->GetData ( 839 Ip6Cfg, 840 Ip6ConfigDataTypeManualAddress, 841 &DataSize, 842 (VOID *) Ip6Addr 843 ); 844 if (EFI_ERROR (Status)) { 845 Status = EFI_DEVICE_ERROR; 846 goto ON_EXIT; 847 } 848 849 for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index ++) { 850 if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) { 851 break; 852 } 853 } 854 if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { 855 Status = EFI_ABORTED; 856 goto ON_EXIT; 857 } 858 } 859 860ON_EXIT: 861 if (MappedEvt != NULL) { 862 Ip6Cfg->UnregisterDataNotify ( 863 Ip6Cfg, 864 Ip6ConfigDataTypeManualAddress, 865 MappedEvt 866 ); 867 gBS->CloseEvent (MappedEvt); 868 } 869 870 if (Ip6Addr != NULL) { 871 FreePool (Ip6Addr); 872 } 873 874 return Status; 875} 876 877/** 878 Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information. 879 880 @param[in] Private Pointer to HTTP_BOOT private data. 881 882 @retval EFI_SUCCESS The S.A.R.R process successfully finished. 883 @retval Others Failed to finish the S.A.R.R process. 884 885**/ 886EFI_STATUS 887HttpBootDhcp6Sarr ( 888 IN HTTP_BOOT_PRIVATE_DATA *Private 889 ) 890{ 891 EFI_DHCP6_PROTOCOL *Dhcp6; 892 EFI_DHCP6_CONFIG_DATA Config; 893 EFI_DHCP6_MODE_DATA Mode; 894 EFI_DHCP6_RETRANSMISSION *Retransmit; 895 EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM]; 896 UINT32 OptCount; 897 UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE]; 898 EFI_STATUS Status; 899 900 Dhcp6 = Private->Dhcp6; 901 ASSERT (Dhcp6 != NULL); 902 903 // 904 // Build options list for the request packet. 905 // 906 OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer); 907 ASSERT (OptCount >0); 908 909 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); 910 if (Retransmit == NULL) { 911 return EFI_OUT_OF_RESOURCES; 912 } 913 914 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); 915 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); 916 917 Config.OptionCount = OptCount; 918 Config.OptionList = OptList; 919 Config.Dhcp6Callback = HttpBootDhcp6CallBack; 920 Config.CallbackContext = Private; 921 Config.IaInfoEvent = NULL; 922 Config.RapidCommit = FALSE; 923 Config.ReconfigureAccept = FALSE; 924 Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ()); 925 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; 926 Config.SolicitRetransmission = Retransmit; 927 Retransmit->Irt = 4; 928 Retransmit->Mrc = 4; 929 Retransmit->Mrt = 32; 930 Retransmit->Mrd = 60; 931 932 // 933 // Configure the DHCPv6 instance for HTTP boot. 934 // 935 Status = Dhcp6->Configure (Dhcp6, &Config); 936 FreePool (Retransmit); 937 if (EFI_ERROR (Status)) { 938 goto ON_EXIT; 939 } 940 // 941 // Initialize the record fields for DHCPv6 offer in private data. 942 // 943 Private->OfferNum = 0; 944 Private->SelectIndex = 0; 945 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 946 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 947 948 // 949 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. 950 // 951 Status = Dhcp6->Start (Dhcp6); 952 if (EFI_ERROR (Status)) { 953 goto ON_EXIT; 954 } 955 956 // 957 // Get the acquired IPv6 address and store them. 958 // 959 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL); 960 if (EFI_ERROR (Status)) { 961 goto ON_EXIT; 962 } 963 964 ASSERT (Mode.Ia->State == Dhcp6Bound); 965 CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS)); 966 967 AsciiPrint ("\n Station IPv6 address is "); 968 HttpBootShowIp6Addr (&Private->StationIp.v6); 969 AsciiPrint ("\n"); 970 971ON_EXIT: 972 if (EFI_ERROR (Status)) { 973 Dhcp6->Stop (Dhcp6); 974 Dhcp6->Configure (Dhcp6, NULL); 975 } else { 976 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); 977 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); 978 Dhcp6->Configure (Dhcp6, &Config); 979 } 980 981 return Status; 982 983} 984 985