PxeBcDhcp4.c revision 0e7f6f50cc7b05a0f6ec541ddce34211794d9c08
1/** @file 2 Functions implementation related with DHCPv4 for UefiPxeBc Driver. 3 4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php. 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#include "PxeBcImpl.h" 17 18// 19// This is a map from the interested DHCP4 option tags' index to the tag value. 20// 21UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = { 22 PXEBC_DHCP4_TAG_BOOTFILE_LEN, 23 PXEBC_DHCP4_TAG_VENDOR, 24 PXEBC_DHCP4_TAG_OVERLOAD, 25 PXEBC_DHCP4_TAG_MSG_TYPE, 26 PXEBC_DHCP4_TAG_SERVER_ID, 27 PXEBC_DHCP4_TAG_CLASS_ID, 28 PXEBC_DHCP4_TAG_BOOTFILE 29}; 30 31// 32// There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec. 33// 34UINT32 mPxeDhcpTimeout[4] = {4, 8, 16, 32}; 35 36 37/** 38 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer. 39 40 @param[in] Buffer Pointer to the option buffer. 41 @param[in] Length Length of the option buffer. 42 @param[in] OptTag Tag of the required option. 43 44 @retval NULL Failed to find the required option. 45 @retval Others The position of the required option. 46 47**/ 48EFI_DHCP4_PACKET_OPTION * 49PxeBcParseDhcp4Options ( 50 IN UINT8 *Buffer, 51 IN UINT32 Length, 52 IN UINT8 OptTag 53 ) 54{ 55 EFI_DHCP4_PACKET_OPTION *Option; 56 UINT32 Offset; 57 58 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer; 59 Offset = 0; 60 61 while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) { 62 63 if (Option->OpCode == OptTag) { 64 // 65 // Found the required option. 66 // 67 return Option; 68 } 69 70 // 71 // Skip the current option to the next. 72 // 73 if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) { 74 Offset++; 75 } else { 76 Offset += Option->Length + 2; 77 } 78 79 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset); 80 } 81 82 return NULL; 83} 84 85 86/** 87 Parse the PXE vender options and extract the information from them. 88 89 @param[in] Dhcp4Option Pointer to vendor options in buffer. 90 @param[in] VendorOption Pointer to structure to store information in vendor options. 91 92**/ 93VOID 94PxeBcParseVendorOptions ( 95 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option, 96 IN PXEBC_VENDOR_OPTION *VendorOption 97 ) 98{ 99 UINT32 *BitMap; 100 UINT8 VendorOptionLen; 101 EFI_DHCP4_PACKET_OPTION *PxeOption; 102 UINT8 Offset; 103 104 BitMap = VendorOption->BitMap; 105 VendorOptionLen = Dhcp4Option->Length; 106 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0]; 107 Offset = 0; 108 109 ASSERT (PxeOption != NULL); 110 111 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) { 112 // 113 // Parse all the interesting PXE vendor options one by one. 114 // 115 switch (PxeOption->OpCode) { 116 117 case PXEBC_VENDOR_TAG_MTFTP_IP: 118 119 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS)); 120 break; 121 122 case PXEBC_VENDOR_TAG_MTFTP_CPORT: 123 124 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort)); 125 break; 126 127 case PXEBC_VENDOR_TAG_MTFTP_SPORT: 128 129 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort)); 130 break; 131 132 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT: 133 134 VendorOption->MtftpTimeout = *PxeOption->Data; 135 break; 136 137 case PXEBC_VENDOR_TAG_MTFTP_DELAY: 138 139 VendorOption->MtftpDelay = *PxeOption->Data; 140 break; 141 142 case PXEBC_VENDOR_TAG_DISCOVER_CTRL: 143 144 VendorOption->DiscoverCtrl = *PxeOption->Data; 145 break; 146 147 case PXEBC_VENDOR_TAG_DISCOVER_MCAST: 148 149 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS)); 150 break; 151 152 case PXEBC_VENDOR_TAG_BOOT_SERVERS: 153 154 VendorOption->BootSvrLen = PxeOption->Length; 155 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data; 156 break; 157 158 case PXEBC_VENDOR_TAG_BOOT_MENU: 159 160 VendorOption->BootMenuLen = PxeOption->Length; 161 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data; 162 break; 163 164 case PXEBC_VENDOR_TAG_MENU_PROMPT: 165 166 VendorOption->MenuPromptLen = PxeOption->Length; 167 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data; 168 break; 169 170 case PXEBC_VENDOR_TAG_MCAST_ALLOC: 171 172 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS)); 173 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock)); 174 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange)); 175 break; 176 177 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES: 178 179 VendorOption->CredTypeLen = PxeOption->Length; 180 VendorOption->CredType = (UINT32 *) PxeOption->Data; 181 break; 182 183 case PXEBC_VENDOR_TAG_BOOT_ITEM: 184 185 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType)); 186 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer)); 187 break; 188 189 default: 190 // 191 // Not interesting PXE vendor options. 192 // 193 break; 194 } 195 196 // 197 // Set the bit map for the special PXE options. 198 // 199 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode); 200 201 // 202 // Continue to the next option. 203 // 204 if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) { 205 Offset++; 206 } else { 207 Offset = (UINT8) (Offset + PxeOption->Length + 2); 208 } 209 210 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset); 211 } 212} 213 214 215/** 216 Build the options buffer for the DHCPv4 request packet. 217 218 @param[in] Private Pointer to PxeBc private data. 219 @param[out] OptList Pointer to the option pointer array. 220 @param[in] Buffer Pointer to the buffer to contain the option list. 221 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option. 222 Otherwise, it is not necessary. 223 224 @return Index The count of the built-in options. 225 226**/ 227UINT32 228PxeBcBuildDhcp4Options ( 229 IN PXEBC_PRIVATE_DATA *Private, 230 OUT EFI_DHCP4_PACKET_OPTION **OptList, 231 IN UINT8 *Buffer, 232 IN BOOLEAN NeedMsgType 233 ) 234{ 235 UINT32 Index; 236 PXEBC_DHCP4_OPTION_ENTRY OptEnt; 237 UINT16 Value; 238 239 Index = 0; 240 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer; 241 242 if (NeedMsgType) { 243 // 244 // Append message type. 245 // 246 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MSG_TYPE; 247 OptList[Index]->Length = 1; 248 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data; 249 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST; 250 Index++; 251 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 252 253 // 254 // Append max message size. 255 // 256 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MAXMSG; 257 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE); 258 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data; 259 Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8); 260 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16)); 261 Index++; 262 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 263 } 264 265 // 266 // Append parameter request list option. 267 // 268 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_PARA_LIST; 269 OptList[Index]->Length = 35; 270 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data; 271 OptEnt.Para->ParaList[0] = PXEBC_DHCP4_TAG_NETMASK; 272 OptEnt.Para->ParaList[1] = PXEBC_DHCP4_TAG_TIME_OFFSET; 273 OptEnt.Para->ParaList[2] = PXEBC_DHCP4_TAG_ROUTER; 274 OptEnt.Para->ParaList[3] = PXEBC_DHCP4_TAG_TIME_SERVER; 275 OptEnt.Para->ParaList[4] = PXEBC_DHCP4_TAG_NAME_SERVER; 276 OptEnt.Para->ParaList[5] = PXEBC_DHCP4_TAG_DNS_SERVER; 277 OptEnt.Para->ParaList[6] = PXEBC_DHCP4_TAG_HOSTNAME; 278 OptEnt.Para->ParaList[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN; 279 OptEnt.Para->ParaList[8] = PXEBC_DHCP4_TAG_DOMAINNAME; 280 OptEnt.Para->ParaList[9] = PXEBC_DHCP4_TAG_ROOTPATH; 281 OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH; 282 OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU; 283 OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL; 284 OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST; 285 OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN; 286 OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER; 287 OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER; 288 OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR; 289 OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP; 290 OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE; 291 OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID; 292 OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1; 293 OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2; 294 OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID; 295 OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP; 296 OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE; 297 OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID; 298 OptEnt.Para->ParaList[27] = 0x80; 299 OptEnt.Para->ParaList[28] = 0x81; 300 OptEnt.Para->ParaList[29] = 0x82; 301 OptEnt.Para->ParaList[30] = 0x83; 302 OptEnt.Para->ParaList[31] = 0x84; 303 OptEnt.Para->ParaList[32] = 0x85; 304 OptEnt.Para->ParaList[33] = 0x86; 305 OptEnt.Para->ParaList[34] = 0x87; 306 Index++; 307 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 308 309 // 310 // Append UUID/Guid-based client identifier option 311 // 312 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UUID; 313 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID); 314 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data; 315 OptEnt.Uuid->Type = 0; 316 Index++; 317 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 318 319 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) { 320 // 321 // Zero the Guid to indicate NOT programable if failed to get system Guid. 322 // 323 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID)); 324 } 325 326 // 327 // Append client network device interface option 328 // 329 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UNDI; 330 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI); 331 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data; 332 333 if (Private->Nii != NULL) { 334 OptEnt.Undi->Type = Private->Nii->Type; 335 OptEnt.Undi->MajorVer = Private->Nii->MajorVer; 336 OptEnt.Undi->MinorVer = Private->Nii->MinorVer; 337 } else { 338 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; 339 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; 340 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; 341 } 342 343 Index++; 344 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 345 346 // 347 // Append client system architecture option 348 // 349 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_ARCH; 350 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH); 351 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data; 352 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); 353 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); 354 Index++; 355 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]); 356 357 // 358 // Append vendor class identify option 359 // 360 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_CLASS_ID; 361 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID); 362 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data; 363 CopyMem ( 364 OptEnt.Clid, 365 DEFAULT_CLASS_ID_DATA, 366 sizeof (PXEBC_DHCP4_OPTION_CLID) 367 ); 368 PxeBcUintnToAscDecWithFormat ( 369 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, 370 OptEnt.Clid->ArchitectureType, 371 sizeof (OptEnt.Clid->ArchitectureType) 372 ); 373 374 if (Private->Nii != NULL) { 375 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName)); 376 PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor)); 377 PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor)); 378 } 379 380 Index++; 381 382 return Index; 383} 384 385 386/** 387 Create a template DHCPv4 packet as a seed. 388 389 @param[out] Seed Pointer to the seed packet. 390 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. 391 392**/ 393VOID 394PxeBcSeedDhcp4Packet ( 395 OUT EFI_DHCP4_PACKET *Seed, 396 IN EFI_UDP4_PROTOCOL *Udp4 397 ) 398{ 399 EFI_SIMPLE_NETWORK_MODE Mode; 400 EFI_DHCP4_HEADER *Header; 401 402 // 403 // Get IfType and HwAddressSize from SNP mode data. 404 // 405 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode); 406 407 Seed->Size = sizeof (EFI_DHCP4_PACKET); 408 Seed->Length = sizeof (Seed->Dhcp4); 409 Header = &Seed->Dhcp4.Header; 410 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER)); 411 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST; 412 Header->HwType = Mode.IfType; 413 Header->HwAddrLen = (UINT8) Mode.HwAddressSize; 414 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen); 415 416 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC; 417 Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP; 418} 419 420 421/** 422 Cache the DHCPv4 packet. 423 424 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet. 425 @param[in] Src Pointer to the DHCPv4 packet to be cached. 426 427**/ 428VOID 429PxeBcCacheDhcp4Packet ( 430 IN EFI_DHCP4_PACKET *Dst, 431 IN EFI_DHCP4_PACKET *Src 432 ) 433{ 434 ASSERT (Dst->Size >= Src->Length); 435 436 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length); 437 Dst->Length = Src->Length; 438} 439 440 441/** 442 Parse the cached DHCPv4 packet, including all the options. 443 444 @param[in] Cache4 Pointer to cached DHCPv4 packet. 445 446 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully. 447 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet. 448 449**/ 450EFI_STATUS 451PxeBcParseDhcp4Packet ( 452 IN PXEBC_DHCP4_PACKET_CACHE *Cache4 453 ) 454{ 455 EFI_DHCP4_PACKET *Offer; 456 EFI_DHCP4_PACKET_OPTION **Options; 457 EFI_DHCP4_PACKET_OPTION *Option; 458 PXEBC_OFFER_TYPE OfferType; 459 UINTN Index; 460 BOOLEAN IsProxyOffer; 461 BOOLEAN IsPxeOffer; 462 UINT8 *Ptr8; 463 464 IsProxyOffer = FALSE; 465 IsPxeOffer = FALSE; 466 467 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList)); 468 ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt)); 469 470 Offer = &Cache4->Packet.Offer; 471 Options = Cache4->OptList; 472 473 // 474 // Parse DHCPv4 options in this offer, and store the pointers. 475 // First, try to parse DHCPv4 options from the DHCP optional parameters field. 476 // 477 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { 478 Options[Index] = PxeBcParseDhcp4Options ( 479 Offer->Dhcp4.Option, 480 GET_OPTION_BUFFER_LEN (Offer), 481 mInterestedDhcp4Tags[Index] 482 ); 483 } 484 // 485 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. 486 // If yes, try to parse options from the BootFileName field, then ServerName field. 487 // 488 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD]; 489 if (Option != NULL) { 490 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) { 491 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { 492 if (Options[Index] == NULL) { 493 Options[Index] = PxeBcParseDhcp4Options ( 494 (UINT8 *) Offer->Dhcp4.Header.BootFileName, 495 sizeof (Offer->Dhcp4.Header.BootFileName), 496 mInterestedDhcp4Tags[Index] 497 ); 498 } 499 } 500 } 501 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) { 502 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { 503 if (Options[Index] == NULL) { 504 Options[Index] = PxeBcParseDhcp4Options ( 505 (UINT8 *) Offer->Dhcp4.Header.ServerName, 506 sizeof (Offer->Dhcp4.Header.ServerName), 507 mInterestedDhcp4Tags[Index] 508 ); 509 } 510 } 511 } 512 } 513 514 // 515 // The offer with "yiaddr" is a proxy offer. 516 // 517 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) { 518 IsProxyOffer = TRUE; 519 } 520 521 // 522 // The offer with "PXEClient" is a PXE offer. 523 // 524 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID]; 525 if ((Option != NULL) && (Option->Length >= 9) && 526 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) { 527 IsPxeOffer = TRUE; 528 } 529 530 // 531 // Parse PXE vendor options in this offer, and store the contents/pointers. 532 // 533 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR]; 534 if (IsPxeOffer && Option != NULL) { 535 PxeBcParseVendorOptions (Option, &Cache4->VendorOpt); 536 } 537 538 // 539 // Parse PXE boot file name: 540 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present. 541 // Otherwise, read from boot file field in DHCP header. 542 // 543 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 544 // 545 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null 546 // terminated string. So force to append null terminated character at the end of string. 547 // 548 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0]; 549 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length; 550 if (*(Ptr8 - 1) != '\0') { 551 *Ptr8 = '\0'; 552 } 553 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) { 554 // 555 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it. 556 // Do not count dhcp option header here, or else will destroy the serverhostname. 557 // 558 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) 559 (&Offer->Dhcp4.Header.BootFileName[0] - 560 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0])); 561 562 } 563 564 // 565 // Determine offer type of the DHCPv4 packet. 566 // 567 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE]; 568 if (Option == NULL || Option->Data[0] == 0) { 569 // 570 // It's a Bootp offer. 571 // 572 OfferType = PxeOfferTypeBootp; 573 574 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]; 575 if (Option == NULL) { 576 // 577 // If the Bootp offer without bootfilename, discard it. 578 // 579 return EFI_DEVICE_ERROR; 580 } 581 } else { 582 583 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { 584 // 585 // It's a PXE10 offer with PXEClient and discover vendor option. 586 // 587 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10; 588 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { 589 // 590 // It's a WFM11a offer with PXEClient and mtftp vendor option. 591 // But multi-cast download is not supported currently, so discard it. 592 // 593 return EFI_DEVICE_ERROR; 594 } else if (IsPxeOffer) { 595 // 596 // It's a BINL offer only with PXEClient. 597 // 598 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl; 599 } else { 600 // 601 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet. 602 // 603 OfferType = PxeOfferTypeDhcpOnly; 604 } 605 } 606 607 Cache4->OfferType = OfferType; 608 609 return EFI_SUCCESS; 610} 611 612 613/** 614 Cache the DHCPv4 ack packet, and parse it on demand. 615 616 @param[in] Private Pointer to PxeBc private data. 617 @param[in] Ack Pointer to the DHCPv4 ack packet. 618 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data. 619 620**/ 621VOID 622PxeBcCopyDhcp4Ack ( 623 IN PXEBC_PRIVATE_DATA *Private, 624 IN EFI_DHCP4_PACKET *Ack, 625 IN BOOLEAN Verified 626 ) 627{ 628 EFI_PXE_BASE_CODE_MODE *Mode; 629 630 Mode = Private->PxeBc.Mode; 631 632 PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack); 633 634 if (Verified) { 635 // 636 // Parse the ack packet and store it into mode data if needed. 637 // 638 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4); 639 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length); 640 Mode->DhcpAckReceived = TRUE; 641 } 642} 643 644 645/** 646 Cache the DHCPv4 proxy offer packet according to the received order. 647 648 @param[in] Private Pointer to PxeBc private data. 649 @param[in] OfferIndex The received order of offer packets. 650 651**/ 652VOID 653PxeBcCopyProxyOffer ( 654 IN PXEBC_PRIVATE_DATA *Private, 655 IN UINT32 OfferIndex 656 ) 657{ 658 EFI_PXE_BASE_CODE_MODE *Mode; 659 EFI_DHCP4_PACKET *Offer; 660 661 ASSERT (OfferIndex < Private->OfferNum); 662 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); 663 664 Mode = Private->PxeBc.Mode; 665 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer; 666 667 // 668 // Cache the proxy offer packet and parse it. 669 // 670 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer); 671 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4); 672 673 // 674 // Store this packet into mode data. 675 // 676 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length); 677 Mode->ProxyOfferReceived = TRUE; 678} 679 680 681/** 682 Retry to request bootfile name by the BINL offer. 683 684 @param[in] Private Pointer to PxeBc private data. 685 @param[in] Index The received order of offer packets. 686 687 @retval EFI_SUCCESS Successfully retried to request bootfile name. 688 @retval EFI_DEVICE_ERROR Failed to retry bootfile name. 689 690**/ 691EFI_STATUS 692PxeBcRetryBinlOffer ( 693 IN PXEBC_PRIVATE_DATA *Private, 694 IN UINT32 Index 695 ) 696{ 697 EFI_DHCP4_PACKET *Offer; 698 EFI_IP_ADDRESS ServerIp; 699 EFI_STATUS Status; 700 PXEBC_DHCP4_PACKET_CACHE *Cache4; 701 EFI_DHCP4_PACKET *Reply; 702 703 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 704 ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl || 705 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl); 706 707 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 708 709 // 710 // Prefer to siaddr in header as next server address. If it's zero, then use option 54. 711 // 712 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) { 713 CopyMem ( 714 &ServerIp.Addr[0], 715 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data, 716 sizeof (EFI_IPv4_ADDRESS) 717 ); 718 } else { 719 CopyMem ( 720 &ServerIp.Addr[0], 721 &Offer->Dhcp4.Header.ServerAddr, 722 sizeof (EFI_IPv4_ADDRESS) 723 ); 724 } 725 726 Private->IsDoDiscover = FALSE; 727 Cache4 = &Private->ProxyOffer.Dhcp4; 728 Reply = &Cache4->Packet.Offer; 729 730 // 731 // Send another request packet for bootfile name. 732 // 733 Status = PxeBcDhcp4Discover ( 734 Private, 735 0, 736 NULL, 737 FALSE, 738 &ServerIp, 739 0, 740 NULL 741 ); 742 if (EFI_ERROR (Status)) { 743 return Status; 744 } 745 746 // 747 // Parse the reply for the last request packet. 748 // 749 Status = PxeBcParseDhcp4Packet (Cache4); 750 if (EFI_ERROR (Status)) { 751 return Status; 752 } 753 754 if (Cache4->OfferType != PxeOfferTypeProxyPxe10 && 755 Cache4->OfferType != PxeOfferTypeProxyWfm11a && 756 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 757 // 758 // This BINL ack doesn't have discovery option set or multicast option set 759 // or bootfile name specified. 760 // 761 return EFI_DEVICE_ERROR; 762 } 763 764 // 765 // Store the reply into mode data. 766 // 767 Private->PxeBc.Mode->ProxyOfferReceived = TRUE; 768 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length); 769 770 return EFI_SUCCESS; 771} 772 773 774/** 775 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount. 776 777 @param[in] Private Pointer to PxeBc private data. 778 @param[in] RcvdOffer Pointer to the received offer packet. 779 780**/ 781VOID 782PxeBcCacheDhcp4Offer ( 783 IN PXEBC_PRIVATE_DATA *Private, 784 IN EFI_DHCP4_PACKET *RcvdOffer 785 ) 786{ 787 PXEBC_DHCP4_PACKET_CACHE *Cache4; 788 EFI_DHCP4_PACKET *Offer; 789 PXEBC_OFFER_TYPE OfferType; 790 791 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM); 792 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4; 793 Offer = &Cache4->Packet.Offer; 794 795 // 796 // Cache the content of DHCPv4 packet firstly. 797 // 798 PxeBcCacheDhcp4Packet (Offer, RcvdOffer); 799 800 // 801 // Validate the DHCPv4 packet, and parse the options and offer type. 802 // 803 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) { 804 return; 805 } 806 807 // 808 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. 809 // 810 OfferType = Cache4->OfferType; 811 ASSERT (OfferType < PxeOfferTypeMax); 812 813 if (OfferType == PxeOfferTypeBootp) { 814 // 815 // It's a Bootp offer, only cache the first one, and discard the others. 816 // 817 if (Private->OfferCount[OfferType] == 0) { 818 Private->OfferIndex[OfferType][0] = Private->OfferNum; 819 Private->OfferCount[OfferType] = 1; 820 } else { 821 return; 822 } 823 } else { 824 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM); 825 if (IS_PROXY_DHCP_OFFER (Offer)) { 826 // 827 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer. 828 // 829 Private->IsProxyRecved = TRUE; 830 831 if (OfferType == PxeOfferTypeProxyBinl) { 832 // 833 // Cache all proxy BINL offers. 834 // 835 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 836 Private->OfferCount[OfferType]++; 837 } else if (Private->OfferCount[OfferType] > 0) { 838 // 839 // Only cache the first PXE10/WFM11a offer, and discard the others. 840 // 841 Private->OfferIndex[OfferType][0] = Private->OfferNum; 842 Private->OfferCount[OfferType] = 1; 843 } else { 844 return ; 845 } 846 } else { 847 // 848 // It's a DHCPv4 offer with yiaddr, and cache them all. 849 // 850 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 851 Private->OfferCount[OfferType]++; 852 } 853 } 854 855 Private->OfferNum++; 856} 857 858 859/** 860 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType. 861 862 @param[in] Private Pointer to PxeBc private data. 863 864**/ 865VOID 866PxeBcSelectDhcp4Offer ( 867 IN PXEBC_PRIVATE_DATA *Private 868 ) 869{ 870 UINT32 Index; 871 UINT32 OfferIndex; 872 EFI_DHCP4_PACKET *Offer; 873 874 Private->SelectIndex = 0; 875 876 if (Private->IsOfferSorted) { 877 // 878 // Select offer by default policy. 879 // 880 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) { 881 // 882 // 1. DhcpPxe10 offer 883 // 884 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1; 885 886 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { 887 // 888 // 2. DhcpWfm11a offer 889 // 890 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1; 891 892 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 893 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { 894 // 895 // 3. DhcpOnly offer and ProxyPxe10 offer. 896 // 897 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 898 Private->SelectProxyType = PxeOfferTypeProxyPxe10; 899 900 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 901 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { 902 // 903 // 4. DhcpOnly offer and ProxyWfm11a offer. 904 // 905 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 906 Private->SelectProxyType = PxeOfferTypeProxyWfm11a; 907 908 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { 909 // 910 // 5. DhcpBinl offer. 911 // 912 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1; 913 914 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 915 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { 916 // 917 // 6. DhcpOnly offer and ProxyBinl offer. 918 // 919 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 920 Private->SelectProxyType = PxeOfferTypeProxyBinl; 921 922 } else { 923 // 924 // 7. DhcpOnly offer with bootfilename. 925 // 926 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) { 927 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index]; 928 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 929 Private->SelectIndex = OfferIndex + 1; 930 break; 931 } 932 } 933 // 934 // 8. Bootp offer with bootfilename. 935 // 936 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0]; 937 if (Private->SelectIndex == 0 && 938 Private->OfferCount[PxeOfferTypeBootp] > 0 && 939 Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 940 Private->SelectIndex = OfferIndex + 1; 941 } 942 } 943 } else { 944 // 945 // Select offer by received order. 946 // 947 for (Index = 0; Index < Private->OfferNum; Index++) { 948 949 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 950 951 if (IS_PROXY_DHCP_OFFER (Offer)) { 952 // 953 // Skip proxy offers 954 // 955 continue; 956 } 957 958 if (!Private->IsProxyRecved && 959 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly && 960 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 961 // 962 // Skip if DhcpOnly offer without any other proxy offers or bootfilename. 963 // 964 continue; 965 } 966 967 // 968 // Record the index of the select offer. 969 // 970 Private->SelectIndex = Index + 1; 971 break; 972 } 973 } 974} 975 976 977/** 978 Handle the DHCPv4 offer packet. 979 980 @param[in] Private Pointer to PxeBc private data. 981 982 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully. 983 @retval EFI_NO_RESPONSE No response to the following request packet. 984 @retval EFI_NOT_FOUND No boot filename received. 985 986**/ 987EFI_STATUS 988PxeBcHandleDhcp4Offer ( 989 IN PXEBC_PRIVATE_DATA *Private 990 ) 991{ 992 PXEBC_DHCP4_PACKET_CACHE *Cache4; 993 EFI_DHCP4_PACKET_OPTION **Options; 994 UINT32 Index; 995 EFI_DHCP4_PACKET *Offer; 996 PXEBC_OFFER_TYPE OfferType; 997 UINT32 ProxyIndex; 998 UINT32 SelectIndex; 999 EFI_STATUS Status; 1000 EFI_PXE_BASE_CODE_MODE *Mode; 1001 EFI_DHCP4_PACKET *Ack; 1002 1003 ASSERT (Private->SelectIndex > 0); 1004 SelectIndex = (UINT32) (Private->SelectIndex - 1); 1005 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); 1006 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4; 1007 Options = Cache4->OptList; 1008 Status = EFI_SUCCESS; 1009 1010 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) { 1011 // 1012 // DhcpBinl offer is selected, so need try to request bootfilename by this offer. 1013 // 1014 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) { 1015 Status = EFI_NO_RESPONSE; 1016 } 1017 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) { 1018 1019 if (Private->IsProxyRecved) { 1020 // 1021 // DhcpOnly offer is selected, so need try to request bootfile name. 1022 // 1023 ProxyIndex = 0; 1024 if (Private->IsOfferSorted) { 1025 // 1026 // The proxy offer should be determined if select by default policy. 1027 // IsOfferSorted means all offers are labeled by OfferIndex. 1028 // 1029 ASSERT (Private->SelectProxyType < PxeOfferTypeMax); 1030 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0); 1031 1032 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) { 1033 // 1034 // Try all the cached ProxyBinl offer one by one to request bootfile name. 1035 // 1036 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) { 1037 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 1038 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index]; 1039 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) { 1040 break; 1041 } 1042 } 1043 if (Index == Private->OfferCount[Private->SelectProxyType]) { 1044 Status = EFI_NO_RESPONSE; 1045 } 1046 } else { 1047 // 1048 // For other proxy offers, only one is buffered. 1049 // 1050 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0]; 1051 } 1052 } else { 1053 // 1054 // The proxy offer should not be determined if select by received order. 1055 // 1056 Status = EFI_NO_RESPONSE; 1057 1058 for (Index = 0; Index < Private->OfferNum; Index++) { 1059 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 1060 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 1061 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType; 1062 if (!IS_PROXY_DHCP_OFFER (Offer)) { 1063 // 1064 // Skip non proxy DHCPv4 offers. 1065 // 1066 continue; 1067 } 1068 1069 if (OfferType == PxeOfferTypeProxyBinl) { 1070 // 1071 // Try all the cached ProxyBinl offer one by one to request bootfile name. 1072 // 1073 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) { 1074 continue; 1075 } 1076 } 1077 1078 Private->SelectProxyType = OfferType; 1079 ProxyIndex = Index; 1080 Status = EFI_SUCCESS; 1081 break; 1082 } 1083 } 1084 1085 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) { 1086 // 1087 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it. 1088 // 1089 PxeBcCopyProxyOffer (Private, ProxyIndex); 1090 } 1091 } else { 1092 // 1093 // Othewise, the bootfile name must be included in DhcpOnly offer. 1094 // 1095 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 1096 Status = EFI_NOT_FOUND; 1097 } 1098 } 1099 } 1100 1101 if (!EFI_ERROR (Status)) { 1102 // 1103 // All PXE boot information is ready by now. 1104 // 1105 Mode = Private->PxeBc.Mode; 1106 Offer = &Cache4->Packet.Offer; 1107 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack; 1108 if (Cache4->OfferType == PxeOfferTypeBootp) { 1109 // 1110 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply 1111 // should be taken as ack. 1112 // 1113 Ack = Offer; 1114 } 1115 1116 PxeBcCopyDhcp4Ack (Private, Ack, TRUE); 1117 Mode->DhcpDiscoverValid = TRUE; 1118 } 1119 1120 return Status; 1121} 1122 1123 1124/** 1125 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver 1126 to intercept events that occurred in the configuration process. 1127 1128 @param[in] This Pointer to the EFI DHCPv4 Protocol. 1129 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure(). 1130 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver. 1131 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a 1132 state transition. 1133 @param[in] Packet The DHCPv4 packet that is going to be sent or already received. 1134 @param[out] NewPacket The packet that is used to replace the above Packet. 1135 1136 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process. 1137 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol 1138 driver will continue to wait for more DHCPOFFER packets until the 1139 retry timeout expires. 1140 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process 1141 and return to the Dhcp4Init or Dhcp4InitReboot state. 1142 1143**/ 1144EFI_STATUS 1145EFIAPI 1146PxeBcDhcp4CallBack ( 1147 IN EFI_DHCP4_PROTOCOL *This, 1148 IN VOID *Context, 1149 IN EFI_DHCP4_STATE CurrentState, 1150 IN EFI_DHCP4_EVENT Dhcp4Event, 1151 IN EFI_DHCP4_PACKET *Packet OPTIONAL, 1152 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL 1153 ) 1154{ 1155 PXEBC_PRIVATE_DATA *Private; 1156 EFI_PXE_BASE_CODE_MODE *Mode; 1157 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; 1158 EFI_DHCP4_PACKET_OPTION *MaxMsgSize; 1159 UINT16 Value; 1160 EFI_STATUS Status; 1161 BOOLEAN Received; 1162 1163 if ((Dhcp4Event != Dhcp4RcvdOffer) && 1164 (Dhcp4Event != Dhcp4SelectOffer) && 1165 (Dhcp4Event != Dhcp4SendDiscover) && 1166 (Dhcp4Event != Dhcp4RcvdAck)) { 1167 return EFI_SUCCESS; 1168 } 1169 1170 Private = (PXEBC_PRIVATE_DATA *) Context; 1171 Mode = Private->PxeBc.Mode; 1172 Callback = Private->PxeBcCallback; 1173 1174 // 1175 // Override the Maximum DHCP Message Size. 1176 // 1177 MaxMsgSize = PxeBcParseDhcp4Options ( 1178 Packet->Dhcp4.Option, 1179 GET_OPTION_BUFFER_LEN (Packet), 1180 PXEBC_DHCP4_TAG_MAXMSG 1181 ); 1182 if (MaxMsgSize != NULL) { 1183 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8); 1184 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value)); 1185 } 1186 1187 // 1188 // Callback to user if any packets sent or received. 1189 // 1190 if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) { 1191 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck); 1192 Status = Callback->Callback ( 1193 Callback, 1194 Private->Function, 1195 Received, 1196 Packet->Length, 1197 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4 1198 ); 1199 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { 1200 return EFI_ABORTED; 1201 } 1202 } 1203 1204 Status = EFI_SUCCESS; 1205 1206 switch (Dhcp4Event) { 1207 1208 case Dhcp4SendDiscover: 1209 // 1210 // Cache the DHCPv4 discover packet to mode data directly. 1211 // It need to check SendGuid as well as Dhcp4SendRequest. 1212 // 1213 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length); 1214 1215 case Dhcp4SendRequest: 1216 if (Mode->SendGUID) { 1217 // 1218 // Send the system Guid instead of the MAC address as the hardware address if required. 1219 // 1220 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) { 1221 // 1222 // Zero the Guid to indicate NOT programable if failed to get system Guid. 1223 // 1224 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID)); 1225 } 1226 Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID); 1227 } 1228 break; 1229 1230 case Dhcp4RcvdOffer: 1231 Status = EFI_NOT_READY; 1232 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { 1233 // 1234 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record 1235 // the OfferIndex and OfferCount. 1236 // 1237 PxeBcCacheDhcp4Offer (Private, Packet); 1238 } 1239 break; 1240 1241 case Dhcp4SelectOffer: 1242 // 1243 // Select offer by the default policy or by order, and record the SelectIndex 1244 // and SelectProxyType. 1245 // 1246 PxeBcSelectDhcp4Offer (Private); 1247 1248 if (Private->SelectIndex == 0) { 1249 Status = EFI_ABORTED; 1250 } else { 1251 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer; 1252 } 1253 break; 1254 1255 case Dhcp4RcvdAck: 1256 // 1257 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data 1258 // without verification. 1259 // 1260 ASSERT (Private->SelectIndex != 0); 1261 1262 PxeBcCopyDhcp4Ack (Private, Packet, FALSE); 1263 break; 1264 1265 default: 1266 break; 1267 } 1268 1269 return Status; 1270} 1271 1272 1273/** 1274 Build and send out the request packet for the bootfile, and parse the reply. 1275 1276 @param[in] Private Pointer to PxeBc private data. 1277 @param[in] Type PxeBc option boot item type. 1278 @param[in] Layer Pointer to option boot item layer. 1279 @param[in] UseBis Use BIS or not. 1280 @param[in] DestIp Pointer to the server address. 1281 @param[in] IpCount The total count of the server address. 1282 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. 1283 1284 @retval EFI_SUCCESS Successfully discovered boot file. 1285 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. 1286 @retval EFI_NOT_FOUND Can't get the PXE reply packet. 1287 @retval Others Failed to discover boot file. 1288 1289**/ 1290EFI_STATUS 1291PxeBcDhcp4Discover ( 1292 IN PXEBC_PRIVATE_DATA *Private, 1293 IN UINT16 Type, 1294 IN UINT16 *Layer, 1295 IN BOOLEAN UseBis, 1296 IN EFI_IP_ADDRESS *DestIp, 1297 IN UINT16 IpCount, 1298 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList 1299 ) 1300{ 1301 EFI_PXE_BASE_CODE_UDP_PORT Sport; 1302 EFI_PXE_BASE_CODE_MODE *Mode; 1303 EFI_DHCP4_PROTOCOL *Dhcp4; 1304 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; 1305 BOOLEAN IsBCast; 1306 EFI_STATUS Status; 1307 UINT16 RepIndex; 1308 UINT16 SrvIndex; 1309 UINT16 TryIndex; 1310 EFI_DHCP4_LISTEN_POINT ListenPoint; 1311 EFI_DHCP4_PACKET *Response; 1312 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; 1313 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; 1314 UINT32 OptCount; 1315 EFI_DHCP4_PACKET_OPTION *PxeOpt; 1316 PXEBC_OPTION_BOOT_ITEM *PxeBootItem; 1317 UINT8 VendorOptLen; 1318 UINT32 Xid; 1319 1320 Mode = Private->PxeBc.Mode; 1321 Dhcp4 = Private->Dhcp4; 1322 Status = EFI_SUCCESS; 1323 1324 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN)); 1325 1326 // 1327 // Use broadcast if destination address not specified. 1328 // 1329 if (DestIp == NULL) { 1330 Sport = PXEBC_DHCP4_S_PORT; 1331 IsBCast = TRUE; 1332 } else { 1333 Sport = PXEBC_BS_DISCOVER_PORT; 1334 IsBCast = FALSE; 1335 } 1336 1337 if (!UseBis && Layer != NULL) { 1338 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; 1339 } 1340 1341 // 1342 // Build all the options for the request packet. 1343 // 1344 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE); 1345 1346 if (Private->IsDoDiscover) { 1347 // 1348 // Add vendor option of PXE_BOOT_ITEM 1349 // 1350 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1); 1351 OptList[OptCount] = AllocateZeroPool (VendorOptLen); 1352 if (OptList[OptCount] == NULL) { 1353 return EFI_OUT_OF_RESOURCES; 1354 } 1355 1356 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR; 1357 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2); 1358 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data; 1359 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM; 1360 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM); 1361 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data; 1362 PxeBootItem->Type = HTONS (Type); 1363 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP; 1364 1365 if (Layer != NULL) { 1366 PxeBootItem->Layer = HTONS (*Layer); 1367 } 1368 1369 OptCount++; 1370 } 1371 1372 // 1373 // Build the request packet with seed packet and option list. 1374 // 1375 Status = Dhcp4->Build ( 1376 Dhcp4, 1377 &Private->SeedPacket, 1378 0, 1379 NULL, 1380 OptCount, 1381 OptList, 1382 &Token.Packet 1383 ); 1384 // 1385 // Free the vendor option of PXE_BOOT_ITEM. 1386 // 1387 if (Private->IsDoDiscover) { 1388 FreePool (OptList[OptCount - 1]); 1389 } 1390 1391 if (EFI_ERROR (Status)) { 1392 return Status; 1393 } 1394 1395 if (Mode->SendGUID) { 1396 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) { 1397 // 1398 // Zero the Guid to indicate NOT programable if failed to get system Guid. 1399 // 1400 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID)); 1401 } 1402 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID); 1403 } 1404 1405 // 1406 // Set fields of the token for the request packet. 1407 // 1408 Xid = NET_RANDOM (NetRandomInitSeed ()); 1409 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid); 1410 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0)); 1411 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); 1412 1413 Token.RemotePort = Sport; 1414 1415 if (IsBCast) { 1416 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff); 1417 } else { 1418 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS)); 1419 } 1420 1421 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS)); 1422 1423 if (!IsBCast) { 1424 Token.ListenPointCount = 1; 1425 Token.ListenPoints = &ListenPoint; 1426 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT; 1427 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS)); 1428 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS)); 1429 } 1430 1431 // 1432 // Send out the request packet to discover the bootfile. 1433 // 1434 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) { 1435 1436 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex); 1437 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1)); 1438 1439 Status = Dhcp4->TransmitReceive (Dhcp4, &Token); 1440 if (Token.Status != EFI_TIMEOUT) { 1441 break; 1442 } 1443 } 1444 1445 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) { 1446 // 1447 // No server response our PXE request 1448 // 1449 Status = EFI_TIMEOUT; 1450 } 1451 1452 if (!EFI_ERROR (Status)) { 1453 1454 RepIndex = 0; 1455 SrvIndex = 0; 1456 Response = Token.ResponseList; 1457 // 1458 // Find the right PXE Reply according to server address. 1459 // 1460 while (RepIndex < Token.ResponseCount) { 1461 1462 while (SrvIndex < IpCount) { 1463 if (SrvList[SrvIndex].AcceptAnyResponse) { 1464 break; 1465 } 1466 if ((SrvList[SrvIndex].Type == Type) && 1467 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) { 1468 break; 1469 } 1470 SrvIndex++; 1471 } 1472 1473 if ((IpCount != SrvIndex) || (IpCount == 0)) { 1474 break; 1475 } 1476 1477 SrvIndex = 0; 1478 RepIndex++; 1479 1480 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size); 1481 } 1482 1483 if (RepIndex < Token.ResponseCount) { 1484 // 1485 // Cache the right PXE reply packet here, set valid flag later. 1486 // Especially for PXE discover packet, store it into mode data here. 1487 // 1488 if (Private->IsDoDiscover) { 1489 PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response); 1490 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length); 1491 } else { 1492 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response); 1493 } 1494 } else { 1495 // 1496 // Not found the right PXE reply packet. 1497 // 1498 Status = EFI_NOT_FOUND; 1499 } 1500 if (Token.ResponseList != NULL) { 1501 FreePool (Token.ResponseList); 1502 } 1503 } 1504 1505 FreePool (Token.Packet); 1506 return Status; 1507} 1508 1509 1510/** 1511 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information. 1512 1513 @param[in] Private Pointer to PxeBc private data. 1514 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL 1515 1516 @retval EFI_SUCCESS The D.O.R.A process successfully finished. 1517 @retval Others Failed to finish the D.O.R.A process. 1518 1519**/ 1520EFI_STATUS 1521PxeBcDhcp4Dora ( 1522 IN PXEBC_PRIVATE_DATA *Private, 1523 IN EFI_DHCP4_PROTOCOL *Dhcp4 1524 ) 1525{ 1526 EFI_PXE_BASE_CODE_MODE *PxeMode; 1527 EFI_DHCP4_CONFIG_DATA Config; 1528 EFI_DHCP4_MODE_DATA Mode; 1529 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; 1530 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; 1531 UINT32 OptCount; 1532 EFI_STATUS Status; 1533 1534 ASSERT (Dhcp4 != NULL); 1535 1536 Status = EFI_SUCCESS; 1537 PxeMode = Private->PxeBc.Mode; 1538 1539 // 1540 // Build option list for the request packet. 1541 // 1542 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE); 1543 ASSERT (OptCount> 0); 1544 1545 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA)); 1546 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1547 1548 Config.OptionCount = OptCount; 1549 Config.OptionList = OptList; 1550 Config.Dhcp4Callback = PxeBcDhcp4CallBack; 1551 Config.CallbackContext = Private; 1552 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES; 1553 Config.DiscoverTimeout = mPxeDhcpTimeout; 1554 1555 // 1556 // Configure the DHCPv4 instance for PXE boot. 1557 // 1558 Status = Dhcp4->Configure (Dhcp4, &Config); 1559 if (EFI_ERROR (Status)) { 1560 goto ON_EXIT; 1561 } 1562 1563 // 1564 // Initialize the record fields for DHCPv4 offer in private data. 1565 // 1566 Private->IsProxyRecved = FALSE; 1567 Private->OfferNum = 0; 1568 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 1569 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 1570 1571 // 1572 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. 1573 // 1574 Status = Dhcp4->Start (Dhcp4, NULL); 1575 if (EFI_ERROR (Status)) { 1576 if (Status == EFI_ICMP_ERROR) { 1577 PxeMode->IcmpErrorReceived = TRUE; 1578 } 1579 goto ON_EXIT; 1580 } 1581 1582 // 1583 // Get the acquired IPv4 address and store them. 1584 // 1585 Status = Dhcp4->GetModeData (Dhcp4, &Mode); 1586 if (EFI_ERROR (Status)) { 1587 goto ON_EXIT; 1588 } 1589 1590 ASSERT (Mode.State == Dhcp4Bound); 1591 1592 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); 1593 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1594 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 1595 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); 1596 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1597 1598 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask); 1599 if (EFI_ERROR (Status)) { 1600 goto ON_EXIT; 1601 } 1602 1603 // 1604 // Check the selected offer whether BINL retry is needed. 1605 // 1606 Status = PxeBcHandleDhcp4Offer (Private); 1607 1608 AsciiPrint ("\n Station IP address is "); 1609 1610 PxeBcShowIp4Addr (&Private->StationIp.v4); 1611 AsciiPrint ("\n"); 1612 1613ON_EXIT: 1614 if (EFI_ERROR (Status)) { 1615 Dhcp4->Stop (Dhcp4); 1616 Dhcp4->Configure (Dhcp4, NULL); 1617 } else { 1618 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1619 Dhcp4->Configure (Dhcp4, &Config); 1620 Private->IsAddressOk = TRUE; 1621 } 1622 1623 return Status; 1624} 1625