1 /** @file 2 Functions implementation related with DHCPv4 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 // This is a map from the interested DHCP4 option tags' index to the tag value. 19 // 20 UINT8 mInterestedDhcp4Tags[HTTP_BOOT_DHCP4_TAG_INDEX_MAX] = { 21 HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN, 22 HTTP_BOOT_DHCP4_TAG_OVERLOAD, 23 HTTP_BOOT_DHCP4_TAG_MSG_TYPE, 24 HTTP_BOOT_DHCP4_TAG_SERVER_ID, 25 HTTP_BOOT_DHCP4_TAG_CLASS_ID, 26 HTTP_BOOT_DHCP4_TAG_BOOTFILE, 27 HTTP_BOOT_DHCP4_TAG_DNS_SERVER 28 }; 29 30 // 31 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec. 32 // 33 UINT32 mHttpDhcpTimeout[4] = {4, 8, 16, 32}; 34 35 /** 36 Build the options buffer for the DHCPv4 request packet. 37 38 @param[in] Private Pointer to HTTP boot driver private data. 39 @param[out] OptList Pointer to the option pointer array. 40 @param[in] Buffer Pointer to the buffer to contain the option list. 41 42 @return Index The count of the built-in options. 43 44 **/ 45 UINT32 46 HttpBootBuildDhcp4Options ( 47 IN HTTP_BOOT_PRIVATE_DATA *Private, 48 OUT EFI_DHCP4_PACKET_OPTION **OptList, 49 IN UINT8 *Buffer 50 ) 51 { 52 HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt; 53 UINT16 Value; 54 UINT32 Index; 55 56 Index = 0; 57 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer; 58 59 // 60 // Append parameter request list option. 61 // 62 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_PARA_LIST; 63 OptList[Index]->Length = 27; 64 OptEnt.Para = (HTTP_BOOT_DHCP4_OPTION_PARA *) OptList[Index]->Data; 65 OptEnt.Para->ParaList[0] = HTTP_BOOT_DHCP4_TAG_NETMASK; 66 OptEnt.Para->ParaList[1] = HTTP_BOOT_DHCP4_TAG_TIME_OFFSET; 67 OptEnt.Para->ParaList[2] = HTTP_BOOT_DHCP4_TAG_ROUTER; 68 OptEnt.Para->ParaList[3] = HTTP_BOOT_DHCP4_TAG_TIME_SERVER; 69 OptEnt.Para->ParaList[4] = HTTP_BOOT_DHCP4_TAG_NAME_SERVER; 70 OptEnt.Para->ParaList[5] = HTTP_BOOT_DHCP4_TAG_DNS_SERVER; 71 OptEnt.Para->ParaList[6] = HTTP_BOOT_DHCP4_TAG_HOSTNAME; 72 OptEnt.Para->ParaList[7] = HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN; 73 OptEnt.Para->ParaList[8] = HTTP_BOOT_DHCP4_TAG_DOMAINNAME; 74 OptEnt.Para->ParaList[9] = HTTP_BOOT_DHCP4_TAG_ROOTPATH; 75 OptEnt.Para->ParaList[10] = HTTP_BOOT_DHCP4_TAG_EXTEND_PATH; 76 OptEnt.Para->ParaList[11] = HTTP_BOOT_DHCP4_TAG_EMTU; 77 OptEnt.Para->ParaList[12] = HTTP_BOOT_DHCP4_TAG_TTL; 78 OptEnt.Para->ParaList[13] = HTTP_BOOT_DHCP4_TAG_BROADCAST; 79 OptEnt.Para->ParaList[14] = HTTP_BOOT_DHCP4_TAG_NIS_DOMAIN; 80 OptEnt.Para->ParaList[15] = HTTP_BOOT_DHCP4_TAG_NIS_SERVER; 81 OptEnt.Para->ParaList[16] = HTTP_BOOT_DHCP4_TAG_NTP_SERVER; 82 OptEnt.Para->ParaList[17] = HTTP_BOOT_DHCP4_TAG_VENDOR; 83 OptEnt.Para->ParaList[18] = HTTP_BOOT_DHCP4_TAG_REQUEST_IP; 84 OptEnt.Para->ParaList[19] = HTTP_BOOT_DHCP4_TAG_LEASE; 85 OptEnt.Para->ParaList[20] = HTTP_BOOT_DHCP4_TAG_SERVER_ID; 86 OptEnt.Para->ParaList[21] = HTTP_BOOT_DHCP4_TAG_T1; 87 OptEnt.Para->ParaList[22] = HTTP_BOOT_DHCP4_TAG_T2; 88 OptEnt.Para->ParaList[23] = HTTP_BOOT_DHCP4_TAG_CLASS_ID; 89 OptEnt.Para->ParaList[25] = HTTP_BOOT_DHCP4_TAG_BOOTFILE; 90 OptEnt.Para->ParaList[26] = HTTP_BOOT_DHCP4_TAG_UUID; 91 Index++; 92 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 93 94 // 95 // Append UUID/Guid-based client identifier option 96 // 97 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UUID; 98 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UUID); 99 OptEnt.Uuid = (HTTP_BOOT_DHCP4_OPTION_UUID *) OptList[Index]->Data; 100 OptEnt.Uuid->Type = 0; 101 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) { 102 // 103 // Zero the Guid to indicate NOT programable if failed to get system Guid. 104 // 105 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID)); 106 } 107 Index++; 108 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 109 110 // 111 // Append client network device interface option 112 // 113 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UNDI; 114 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI); 115 OptEnt.Undi = (HTTP_BOOT_DHCP4_OPTION_UNDI *) OptList[Index]->Data; 116 117 if (Private->Nii != NULL) { 118 OptEnt.Undi->Type = Private->Nii->Type; 119 OptEnt.Undi->MajorVer = Private->Nii->MajorVer; 120 OptEnt.Undi->MinorVer = Private->Nii->MinorVer; 121 } else { 122 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; 123 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; 124 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; 125 } 126 127 Index++; 128 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 129 130 // 131 // Append client system architecture option 132 // 133 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_ARCH; 134 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH); 135 OptEnt.Arch = (HTTP_BOOT_DHCP4_OPTION_ARCH *) OptList[Index]->Data; 136 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE); 137 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); 138 Index++; 139 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 140 141 // 142 // Append vendor class identify option 143 // 144 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_CLASS_ID; 145 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_CLID); 146 OptEnt.Clid = (HTTP_BOOT_DHCP4_OPTION_CLID *) OptList[Index]->Data; 147 CopyMem ( 148 OptEnt.Clid, 149 DEFAULT_CLASS_ID_DATA, 150 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID) 151 ); 152 HttpBootUintnToAscDecWithFormat ( 153 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE, 154 OptEnt.Clid->ArchitectureType, 155 sizeof (OptEnt.Clid->ArchitectureType) 156 ); 157 158 if (Private->Nii != NULL) { 159 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName)); 160 HttpBootUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor)); 161 HttpBootUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor)); 162 } 163 164 Index++; 165 166 return Index; 167 } 168 169 /** 170 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer. 171 172 @param[in] Buffer Pointer to the option buffer. 173 @param[in] Length Length of the option buffer. 174 @param[in] OptTag Tag of the required option. 175 176 @retval NULL Failed to find the required option. 177 @retval Others The position of the required option. 178 179 **/ 180 EFI_DHCP4_PACKET_OPTION * 181 HttpBootParseDhcp4Options ( 182 IN UINT8 *Buffer, 183 IN UINT32 Length, 184 IN UINT8 OptTag 185 ) 186 { 187 EFI_DHCP4_PACKET_OPTION *Option; 188 UINT32 Offset; 189 190 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer; 191 Offset = 0; 192 193 while (Offset < Length && Option->OpCode != HTTP_BOOT_DHCP4_TAG_EOP) { 194 195 if (Option->OpCode == OptTag) { 196 // 197 // Found the required option. 198 // 199 return Option; 200 } 201 202 // 203 // Skip the current option to the next. 204 // 205 if (Option->OpCode == HTTP_BOOT_DHCP4_TAG_PAD) { 206 Offset++; 207 } else { 208 Offset += Option->Length + 2; 209 } 210 211 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset); 212 } 213 214 return NULL; 215 } 216 217 /** 218 Cache the DHCPv4 packet. 219 220 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet. 221 @param[in] Src Pointer to the DHCPv4 packet to be cached. 222 223 **/ 224 VOID 225 HttpBootCacheDhcp4Packet ( 226 IN EFI_DHCP4_PACKET *Dst, 227 IN EFI_DHCP4_PACKET *Src 228 ) 229 { 230 ASSERT (Dst->Size >= Src->Length); 231 232 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length); 233 Dst->Length = Src->Length; 234 } 235 236 /** 237 Parse the cached DHCPv4 packet, including all the options. 238 239 @param[in] Cache4 Pointer to cached DHCPv4 packet. 240 241 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully. 242 @retval EFI_DEVICE_ERROR Failed to parse an invalid packet. 243 244 **/ 245 EFI_STATUS 246 HttpBootParseDhcp4Packet ( 247 IN HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4 248 ) 249 { 250 EFI_DHCP4_PACKET *Offer; 251 EFI_DHCP4_PACKET_OPTION **Options; 252 UINTN Index; 253 EFI_DHCP4_PACKET_OPTION *Option; 254 BOOLEAN IsProxyOffer; 255 BOOLEAN IsHttpOffer; 256 BOOLEAN IsDnsOffer; 257 BOOLEAN IpExpressedUri; 258 UINT8 *Ptr8; 259 EFI_STATUS Status; 260 HTTP_BOOT_OFFER_TYPE OfferType; 261 EFI_IPv4_ADDRESS IpAddr; 262 263 IsDnsOffer = FALSE; 264 IpExpressedUri = FALSE; 265 IsProxyOffer = FALSE; 266 IsHttpOffer = FALSE; 267 268 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList)); 269 270 Offer = &Cache4->Packet.Offer; 271 Options = Cache4->OptList; 272 273 // 274 // Parse DHCPv4 options in this offer, and store the pointers. 275 // First, try to parse DHCPv4 options from the DHCP optional parameters field. 276 // 277 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) { 278 Options[Index] = HttpBootParseDhcp4Options ( 279 Offer->Dhcp4.Option, 280 GET_OPTION_BUFFER_LEN (Offer), 281 mInterestedDhcp4Tags[Index] 282 ); 283 } 284 // 285 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. 286 // If yes, try to parse options from the BootFileName field, then ServerName field. 287 // 288 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD]; 289 if (Option != NULL) { 290 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) { 291 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) { 292 if (Options[Index] == NULL) { 293 Options[Index] = HttpBootParseDhcp4Options ( 294 (UINT8 *) Offer->Dhcp4.Header.BootFileName, 295 sizeof (Offer->Dhcp4.Header.BootFileName), 296 mInterestedDhcp4Tags[Index] 297 ); 298 } 299 } 300 } 301 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) { 302 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) { 303 if (Options[Index] == NULL) { 304 Options[Index] = HttpBootParseDhcp4Options ( 305 (UINT8 *) Offer->Dhcp4.Header.ServerName, 306 sizeof (Offer->Dhcp4.Header.ServerName), 307 mInterestedDhcp4Tags[Index] 308 ); 309 } 310 } 311 } 312 } 313 314 // 315 // The offer with "yiaddr" is a proxy offer. 316 // 317 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) { 318 IsProxyOffer = TRUE; 319 } 320 321 // 322 // The offer with "HTTPClient" is a Http offer. 323 // 324 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID]; 325 if ((Option != NULL) && (Option->Length >= 9) && 326 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) { 327 IsHttpOffer = TRUE; 328 } 329 330 // 331 // The offer with Domain Server is a DNS offer. 332 // 333 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER]; 334 if (Option != NULL) { 335 IsDnsOffer = TRUE; 336 } 337 338 // 339 // Parse boot file name: 340 // Boot URI information is provided thru 'file' field in DHCP Header or option 67. 341 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present. 342 // Otherwise, read from boot file field in DHCP header. 343 // 344 if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 345 // 346 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null 347 // terminated string. So force to append null terminated character at the end of string. 348 // 349 Ptr8 = (UINT8*)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0]; 350 Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length; 351 if (*(Ptr8 - 1) != '\0') { 352 *Ptr8 = '\0'; 353 } 354 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) { 355 // 356 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it. 357 // Do not count dhcp option header here, or else will destroy the serverhostname. 358 // 359 Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) 360 (&Offer->Dhcp4.Header.BootFileName[0] - 361 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0])); 362 } 363 364 // 365 // Http offer must have a boot URI. 366 // 367 if (IsHttpOffer && Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 368 return EFI_DEVICE_ERROR; 369 } 370 371 // 372 // Try to retrieve the IP of HTTP server from URI. 373 // 374 if (IsHttpOffer) { 375 Status = HttpParseUrl ( 376 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data, 377 (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data), 378 FALSE, 379 &Cache4->UriParser 380 ); 381 if (EFI_ERROR (Status)) { 382 return EFI_DEVICE_ERROR; 383 } 384 385 Status = HttpUrlGetIp4 ( 386 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data, 387 Cache4->UriParser, 388 &IpAddr 389 ); 390 IpExpressedUri = !EFI_ERROR (Status); 391 } 392 393 // 394 // Determine offer type of the DHCPv4 packet. 395 // 396 if (IsHttpOffer) { 397 if (IpExpressedUri) { 398 OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri; 399 } else { 400 if (!IsProxyOffer) { 401 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri; 402 } else { 403 OfferType = HttpOfferTypeProxyNameUri; 404 } 405 } 406 407 } else { 408 if (!IsProxyOffer) { 409 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly; 410 } else { 411 return EFI_DEVICE_ERROR; 412 } 413 } 414 415 Cache4->OfferType = OfferType; 416 return EFI_SUCCESS; 417 } 418 419 /** 420 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount. 421 422 @param[in] Private Pointer to HTTP boot driver private data. 423 @param[in] RcvdOffer Pointer to the received offer packet. 424 425 **/ 426 VOID 427 HttpBootCacheDhcp4Offer ( 428 IN HTTP_BOOT_PRIVATE_DATA *Private, 429 IN EFI_DHCP4_PACKET *RcvdOffer 430 ) 431 { 432 HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4; 433 EFI_DHCP4_PACKET *Offer; 434 HTTP_BOOT_OFFER_TYPE OfferType; 435 436 ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM); 437 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4; 438 Offer = &Cache4->Packet.Offer; 439 440 // 441 // Cache the content of DHCPv4 packet firstly. 442 // 443 HttpBootCacheDhcp4Packet (Offer, RcvdOffer); 444 445 // 446 // Validate the DHCPv4 packet, and parse the options and offer type. 447 // 448 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) { 449 return; 450 } 451 452 // 453 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. 454 // 455 OfferType = Cache4->OfferType; 456 ASSERT (OfferType < HttpOfferTypeMax); 457 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM); 458 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 459 Private->OfferCount[OfferType]++; 460 Private->OfferNum++; 461 } 462 463 /** 464 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType. 465 466 @param[in] Private Pointer to HTTP boot driver private data. 467 468 **/ 469 VOID 470 HttpBootSelectDhcpOffer ( 471 IN HTTP_BOOT_PRIVATE_DATA *Private 472 ) 473 { 474 Private->SelectIndex = 0; 475 Private->SelectProxyType = HttpOfferTypeMax; 476 477 // 478 // Priority1: HttpOfferTypeDhcpIpUri 479 // Priority2: HttpOfferTypeDhcpNameUriDns 480 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri 481 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri 482 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri 483 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri 484 // 485 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) { 486 487 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1; 488 489 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) { 490 491 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1; 492 493 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 && 494 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) { 495 496 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1; 497 Private->SelectProxyType = HttpOfferTypeProxyIpUri; 498 499 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 && 500 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) { 501 502 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1; 503 Private->SelectProxyType = HttpOfferTypeProxyIpUri; 504 505 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 && 506 Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) { 507 508 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1; 509 Private->SelectProxyType = HttpOfferTypeProxyNameUri; 510 511 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 && 512 Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) { 513 514 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1; 515 Private->SelectProxyType = HttpOfferTypeDhcpNameUri; 516 } 517 } 518 519 520 /** 521 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver 522 to intercept events that occurred in the configuration process. 523 524 @param[in] This Pointer to the EFI DHCPv4 Protocol. 525 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure(). 526 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver. 527 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a 528 state transition. 529 @param[in] Packet The DHCPv4 packet that is going to be sent or already received. 530 @param[out] NewPacket The packet that is used to replace the above Packet. 531 532 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process. 533 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol 534 driver will continue to wait for more DHCPOFFER packets until the 535 retry timeout expires. 536 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process 537 and return to the Dhcp4Init or Dhcp4InitReboot state. 538 539 **/ 540 EFI_STATUS 541 EFIAPI 542 HttpBootDhcp4CallBack ( 543 IN EFI_DHCP4_PROTOCOL *This, 544 IN VOID *Context, 545 IN EFI_DHCP4_STATE CurrentState, 546 IN EFI_DHCP4_EVENT Dhcp4Event, 547 IN EFI_DHCP4_PACKET *Packet OPTIONAL, 548 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL 549 ) 550 { 551 HTTP_BOOT_PRIVATE_DATA *Private; 552 EFI_DHCP4_PACKET_OPTION *MaxMsgSize; 553 UINT16 Value; 554 EFI_STATUS Status; 555 556 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) { 557 return EFI_SUCCESS; 558 } 559 560 Private = (HTTP_BOOT_PRIVATE_DATA *) Context; 561 562 // 563 // Override the Maximum DHCP Message Size. 564 // 565 MaxMsgSize = HttpBootParseDhcp4Options ( 566 Packet->Dhcp4.Option, 567 GET_OPTION_BUFFER_LEN (Packet), 568 HTTP_BOOT_DHCP4_TAG_MAXMSG 569 ); 570 if (MaxMsgSize != NULL) { 571 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE); 572 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value)); 573 } 574 575 Status = EFI_SUCCESS; 576 switch (Dhcp4Event) { 577 case Dhcp4RcvdOffer: 578 Status = EFI_NOT_READY; 579 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) { 580 // 581 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record 582 // the OfferIndex and OfferCount. 583 // 584 HttpBootCacheDhcp4Offer (Private, Packet); 585 } 586 break; 587 588 case Dhcp4SelectOffer: 589 // 590 // Select offer according to the priority in UEFI spec, and record the SelectIndex 591 // and SelectProxyType. 592 // 593 HttpBootSelectDhcpOffer (Private); 594 595 if (Private->SelectIndex == 0) { 596 Status = EFI_ABORTED; 597 } else { 598 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer; 599 } 600 break; 601 602 default: 603 break; 604 } 605 606 return Status; 607 } 608 609 /** 610 This function will register the IPv4 gateway address to the network device. 611 612 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 613 614 @retval EFI_SUCCESS The new IP configuration has been configured successfully. 615 @retval Others Failed to configure the address. 616 617 **/ 618 EFI_STATUS 619 HttpBootRegisterIp4Gateway ( 620 IN HTTP_BOOT_PRIVATE_DATA *Private 621 ) 622 { 623 EFI_STATUS Status; 624 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; 625 626 ASSERT (!Private->UsingIpv6); 627 628 Ip4Config2 = Private->Ip4Config2; 629 630 // 631 // Configure the gateway if valid. 632 // 633 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) { 634 Status = Ip4Config2->SetData ( 635 Ip4Config2, 636 Ip4Config2DataTypeGateway, 637 sizeof (EFI_IPv4_ADDRESS), 638 &Private->GatewayIp 639 ); 640 if (EFI_ERROR (Status)) { 641 return Status; 642 } 643 } 644 645 return EFI_SUCCESS; 646 } 647 648 /** 649 This function will register the default DNS addresses to the network device. 650 651 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA. 652 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes. 653 @param[in] DnsServerData Point a list of DNS server address in an array 654 of EFI_IPv4_ADDRESS instances. 655 656 @retval EFI_SUCCESS The DNS configuration has been configured successfully. 657 @retval Others Failed to configure the address. 658 659 **/ 660 EFI_STATUS 661 HttpBootRegisterIp4Dns ( 662 IN HTTP_BOOT_PRIVATE_DATA *Private, 663 IN UINTN DataLength, 664 IN VOID *DnsServerData 665 ) 666 { 667 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; 668 669 ASSERT (!Private->UsingIpv6); 670 671 Ip4Config2 = Private->Ip4Config2; 672 673 return Ip4Config2->SetData ( 674 Ip4Config2, 675 Ip4Config2DataTypeDnsServer, 676 DataLength, 677 DnsServerData 678 ); 679 } 680 681 682 /** 683 This function will switch the IP4 configuration policy to Static. 684 685 @param[in] Private Pointer to HTTP boot driver private data. 686 687 @retval EFI_SUCCESS The policy is already configured to static. 688 @retval Others Other error as indicated.. 689 690 **/ 691 EFI_STATUS 692 HttpBootSetIp4Policy ( 693 IN HTTP_BOOT_PRIVATE_DATA *Private 694 ) 695 { 696 EFI_IP4_CONFIG2_POLICY Policy; 697 EFI_STATUS Status; 698 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; 699 UINTN DataSize; 700 701 Ip4Config2 = Private->Ip4Config2; 702 703 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY); 704 Status = Ip4Config2->GetData ( 705 Ip4Config2, 706 Ip4Config2DataTypePolicy, 707 &DataSize, 708 &Policy 709 ); 710 if (EFI_ERROR (Status)) { 711 return Status; 712 } 713 714 if (Policy != Ip4Config2PolicyStatic) { 715 Policy = Ip4Config2PolicyStatic; 716 Status= Ip4Config2->SetData ( 717 Ip4Config2, 718 Ip4Config2DataTypePolicy, 719 sizeof (EFI_IP4_CONFIG2_POLICY), 720 &Policy 721 ); 722 if (EFI_ERROR (Status)) { 723 return Status; 724 } 725 } 726 727 return EFI_SUCCESS; 728 } 729 730 /** 731 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information. 732 733 @param[in] Private Pointer to HTTP boot driver private data. 734 735 @retval EFI_SUCCESS The D.O.R.A process successfully finished. 736 @retval Others Failed to finish the D.O.R.A process. 737 738 **/ 739 EFI_STATUS 740 HttpBootDhcp4Dora ( 741 IN HTTP_BOOT_PRIVATE_DATA *Private 742 ) 743 { 744 EFI_DHCP4_PROTOCOL *Dhcp4; 745 UINT32 OptCount; 746 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM]; 747 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE]; 748 EFI_DHCP4_CONFIG_DATA Config; 749 EFI_STATUS Status; 750 EFI_DHCP4_MODE_DATA Mode; 751 752 Dhcp4 = Private->Dhcp4; 753 ASSERT (Dhcp4 != NULL); 754 755 Status = HttpBootSetIp4Policy (Private); 756 if (EFI_ERROR (Status)) { 757 return Status; 758 } 759 760 // 761 // Build option list for the request packet. 762 // 763 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer); 764 ASSERT (OptCount > 0); 765 766 ZeroMem (&Config, sizeof(Config)); 767 Config.OptionCount = OptCount; 768 Config.OptionList = OptList; 769 Config.Dhcp4Callback = HttpBootDhcp4CallBack; 770 Config.CallbackContext = Private; 771 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES; 772 Config.DiscoverTimeout = mHttpDhcpTimeout; 773 774 // 775 // Configure the DHCPv4 instance for HTTP boot. 776 // 777 Status = Dhcp4->Configure (Dhcp4, &Config); 778 if (EFI_ERROR (Status)) { 779 goto ON_EXIT; 780 } 781 782 // 783 // Initialize the record fields for DHCPv4 offer in private data. 784 // 785 Private->OfferNum = 0; 786 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 787 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 788 789 // 790 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. 791 // 792 Status = Dhcp4->Start (Dhcp4, NULL); 793 if (EFI_ERROR (Status)) { 794 goto ON_EXIT; 795 } 796 797 // 798 // Get the acquired IPv4 address and store them. 799 // 800 Status = Dhcp4->GetModeData (Dhcp4, &Mode); 801 if (EFI_ERROR (Status)) { 802 goto ON_EXIT; 803 } 804 805 ASSERT (Mode.State == Dhcp4Bound); 806 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); 807 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 808 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 809 810 Status = HttpBootRegisterIp4Gateway (Private); 811 if (EFI_ERROR (Status)) { 812 goto ON_EXIT; 813 } 814 815 AsciiPrint ("\n Station IP address is "); 816 HttpBootShowIp4Addr (&Private->StationIp.v4); 817 AsciiPrint ("\n"); 818 819 ON_EXIT: 820 if (EFI_ERROR (Status)) { 821 Dhcp4->Stop (Dhcp4); 822 Dhcp4->Configure (Dhcp4, NULL); 823 } else { 824 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 825 Dhcp4->Configure (Dhcp4, &Config); 826 } 827 828 return Status; 829 } 830