1 /** @file 2 Functions implementation related with DHCPv6 for HTTP boot driver. 3 4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials are licensed and made available under 6 the terms and conditions of the BSD License that accompanies this distribution. 7 The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php. 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT 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 **/ 27 UINT32 28 HttpBootBuildDhcp6Options ( 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 **/ 138 EFI_DHCP6_PACKET_OPTION * 139 HttpBootParseDhcp6Options ( 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 **/ 178 EFI_STATUS 179 HttpBootParseDhcp6Packet ( 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 **/ 329 VOID 330 HttpBootCacheDhcp6Packet ( 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 **/ 348 VOID 349 HttpBootCacheDhcp6Offer ( 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 **/ 402 EFI_STATUS 403 EFIAPI 404 HttpBootDhcp6CallBack ( 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 **/ 477 EFI_STATUS 478 HttpBootCheckRouteTable ( 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 569 ON_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 **/ 592 EFI_STATUS 593 HttpBootSetIp6Policy ( 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 **/ 645 EFI_STATUS 646 HttpBootSetIp6Dns ( 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 **/ 675 EFI_STATUS 676 HttpBootSetIp6Gateway ( 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 **/ 713 EFI_STATUS 714 HttpBootSetIp6Address ( 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 860 ON_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 **/ 886 EFI_STATUS 887 HttpBootDhcp6Sarr ( 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 971 ON_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