PxeBcDhcp4.c revision 9063c328dff827ef9deb1ce0dde75112c496e072
1/** @file 2 Functions implementation related with DHCPv4 for UefiPxeBc Driver. 3 4 Copyright (c) 2009 - 2012, 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 // 476 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { 477 Options[Index] = PxeBcParseDhcp4Options ( 478 Offer->Dhcp4.Option, 479 GET_OPTION_BUFFER_LEN (Offer), 480 mInterestedDhcp4Tags[Index] 481 ); 482 } 483 484 // 485 // The offer with "yiaddr" is a proxy offer. 486 // 487 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) { 488 IsProxyOffer = TRUE; 489 } 490 491 // 492 // The offer with "PXEClient" is a PXE offer. 493 // 494 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID]; 495 if ((Option != NULL) && (Option->Length >= 9) && 496 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) { 497 IsPxeOffer = TRUE; 498 } 499 500 // 501 // Parse PXE vendor options in this offer, and store the contents/pointers. 502 // 503 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR]; 504 if (IsPxeOffer && Option != NULL) { 505 PxeBcParseVendorOptions (Option, &Cache4->VendorOpt); 506 } 507 508 // 509 // Check whether bootfilename and serverhostname overloaded, refers to rfc-2132 in details. 510 // If overloaded, parse the buffer as nested DHCPv4 options, or else just parse as bootfilename 511 // and serverhostname option. 512 // 513 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD]; 514 if (Option != NULL && (Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) { 515 516 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = PxeBcParseDhcp4Options ( 517 (UINT8 *) Offer->Dhcp4.Header.BootFileName, 518 sizeof (Offer->Dhcp4.Header.BootFileName), 519 PXEBC_DHCP4_TAG_BOOTFILE 520 ); 521 // 522 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null 523 // terminated string. So force to append null terminated character at the end of string. 524 // 525 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 526 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0]; 527 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length; 528 *Ptr8 = '\0'; 529 } 530 531 } else if ((Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) && 532 (Offer->Dhcp4.Header.BootFileName[0] != 0)) { 533 // 534 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it. 535 // Do not count dhcp option header here, or else will destory the serverhostname. 536 // 537 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) 538 (&Offer->Dhcp4.Header.BootFileName[0] - 539 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0])); 540 541 } 542 543 // 544 // Determine offer type of the DHCPv4 packet. 545 // 546 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE]; 547 if (Option == NULL || Option->Data[0] == 0) { 548 // 549 // It's a Bootp offer. 550 // 551 OfferType = PxeOfferTypeBootp; 552 553 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]; 554 if (Option == NULL) { 555 // 556 // If the Bootp offer without bootfilename, discard it. 557 // 558 return EFI_DEVICE_ERROR; 559 } 560 } else { 561 562 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { 563 // 564 // It's a PXE10 offer with PXEClient and discover vendor option. 565 // 566 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10; 567 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { 568 // 569 // It's a WFM11a offer with PXEClient and mtftp vendor option. 570 // But multi-cast download is not supported currently, so discard it. 571 // 572 return EFI_DEVICE_ERROR; 573 } else if (IsPxeOffer) { 574 // 575 // It's a BINL offer only with PXEClient. 576 // 577 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl; 578 } else { 579 // 580 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet. 581 // 582 OfferType = PxeOfferTypeDhcpOnly; 583 } 584 } 585 586 Cache4->OfferType = OfferType; 587 588 return EFI_SUCCESS; 589} 590 591 592/** 593 Cache the DHCPv4 ack packet, and parse it on demand. 594 595 @param[in] Private Pointer to PxeBc private data. 596 @param[in] Ack Pointer to the DHCPv4 ack packet. 597 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data. 598 599**/ 600VOID 601PxeBcCopyDhcp4Ack ( 602 IN PXEBC_PRIVATE_DATA *Private, 603 IN EFI_DHCP4_PACKET *Ack, 604 IN BOOLEAN Verified 605 ) 606{ 607 EFI_PXE_BASE_CODE_MODE *Mode; 608 609 Mode = Private->PxeBc.Mode; 610 611 PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack); 612 613 if (Verified) { 614 // 615 // Parse the ack packet and store it into mode data if needed. 616 // 617 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4); 618 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length); 619 Mode->DhcpAckReceived = TRUE; 620 } 621} 622 623 624/** 625 Cache the DHCPv4 proxy offer packet according to the received order. 626 627 @param[in] Private Pointer to PxeBc private data. 628 @param[in] OfferIndex The received order of offer packets. 629 630**/ 631VOID 632PxeBcCopyProxyOffer ( 633 IN PXEBC_PRIVATE_DATA *Private, 634 IN UINT32 OfferIndex 635 ) 636{ 637 EFI_PXE_BASE_CODE_MODE *Mode; 638 EFI_DHCP4_PACKET *Offer; 639 640 ASSERT (OfferIndex < Private->OfferNum); 641 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); 642 643 Mode = Private->PxeBc.Mode; 644 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer; 645 646 // 647 // Cache the proxy offer packet and parse it. 648 // 649 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer); 650 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4); 651 652 // 653 // Store this packet into mode data. 654 // 655 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length); 656 Mode->ProxyOfferReceived = TRUE; 657} 658 659 660/** 661 Retry to request bootfile name by the BINL offer. 662 663 @param[in] Private Pointer to PxeBc private data. 664 @param[in] Index The received order of offer packets. 665 666 @retval EFI_SUCCESS Successfully retried to request bootfile name. 667 @retval EFI_DEVICE_ERROR Failed to retry bootfile name. 668 669**/ 670EFI_STATUS 671PxeBcRetryBinlOffer ( 672 IN PXEBC_PRIVATE_DATA *Private, 673 IN UINT32 Index 674 ) 675{ 676 EFI_DHCP4_PACKET *Offer; 677 EFI_IP_ADDRESS ServerIp; 678 EFI_STATUS Status; 679 PXEBC_DHCP4_PACKET_CACHE *Cache4; 680 EFI_DHCP4_PACKET *Reply; 681 682 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 683 ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl || 684 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl); 685 686 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 687 688 // 689 // Prefer to siaddr in header as next server address. If it's zero, then use option 54. 690 // 691 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) { 692 CopyMem ( 693 &ServerIp.Addr[0], 694 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data, 695 sizeof (EFI_IPv4_ADDRESS) 696 ); 697 } else { 698 CopyMem ( 699 &ServerIp.Addr[0], 700 &Offer->Dhcp4.Header.ServerAddr, 701 sizeof (EFI_IPv4_ADDRESS) 702 ); 703 } 704 705 Private->IsDoDiscover = FALSE; 706 Cache4 = &Private->ProxyOffer.Dhcp4; 707 Reply = &Cache4->Packet.Offer; 708 709 // 710 // Send another request packet for bootfile name. 711 // 712 Status = PxeBcDhcp4Discover ( 713 Private, 714 0, 715 NULL, 716 FALSE, 717 &ServerIp, 718 0, 719 NULL 720 ); 721 if (EFI_ERROR (Status)) { 722 return Status; 723 } 724 725 // 726 // Parse the reply for the last request packet. 727 // 728 Status = PxeBcParseDhcp4Packet (Cache4); 729 if (EFI_ERROR (Status)) { 730 return Status; 731 } 732 733 if (Cache4->OfferType != PxeOfferTypeProxyPxe10 && 734 Cache4->OfferType != PxeOfferTypeProxyWfm11a && 735 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 736 // 737 // This BINL ack doesn't have discovery option set or multicast option set 738 // or bootfile name specified. 739 // 740 return EFI_DEVICE_ERROR; 741 } 742 743 // 744 // Store the reply into mode data. 745 // 746 Private->PxeBc.Mode->ProxyOfferReceived = TRUE; 747 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length); 748 749 return EFI_SUCCESS; 750} 751 752 753/** 754 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount. 755 756 @param[in] Private Pointer to PxeBc private data. 757 @param[in] RcvdOffer Pointer to the received offer packet. 758 759**/ 760VOID 761PxeBcCacheDhcp4Offer ( 762 IN PXEBC_PRIVATE_DATA *Private, 763 IN EFI_DHCP4_PACKET *RcvdOffer 764 ) 765{ 766 PXEBC_DHCP4_PACKET_CACHE *Cache4; 767 EFI_DHCP4_PACKET *Offer; 768 PXEBC_OFFER_TYPE OfferType; 769 770 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM); 771 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4; 772 Offer = &Cache4->Packet.Offer; 773 774 // 775 // Cache the content of DHCPv4 packet firstly. 776 // 777 PxeBcCacheDhcp4Packet (Offer, RcvdOffer); 778 779 // 780 // Validate the DHCPv4 packet, and parse the options and offer type. 781 // 782 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) { 783 return; 784 } 785 786 // 787 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount. 788 // 789 OfferType = Cache4->OfferType; 790 ASSERT (OfferType < PxeOfferTypeMax); 791 792 if (OfferType == PxeOfferTypeBootp) { 793 // 794 // It's a Bootp offer, only cache the first one, and discard the others. 795 // 796 if (Private->OfferCount[OfferType] == 0) { 797 Private->OfferIndex[OfferType][0] = Private->OfferNum; 798 Private->OfferCount[OfferType] = 1; 799 } else { 800 return; 801 } 802 } else { 803 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM); 804 if (IS_PROXY_DHCP_OFFER (Offer)) { 805 // 806 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer. 807 // 808 Private->IsProxyRecved = TRUE; 809 810 if (OfferType == PxeOfferTypeProxyBinl) { 811 // 812 // Cache all proxy BINL offers. 813 // 814 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 815 Private->OfferCount[OfferType]++; 816 } else if (Private->OfferCount[OfferType] > 0) { 817 // 818 // Only cache the first PXE10/WFM11a offer, and discard the others. 819 // 820 Private->OfferIndex[OfferType][0] = Private->OfferNum; 821 Private->OfferCount[OfferType] = 1; 822 } else { 823 return ; 824 } 825 } else { 826 // 827 // It's a DHCPv4 offer with yiaddr, and cache them all. 828 // 829 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; 830 Private->OfferCount[OfferType]++; 831 } 832 } 833 834 Private->OfferNum++; 835} 836 837 838/** 839 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType. 840 841 @param[in] Private Pointer to PxeBc private data. 842 843**/ 844VOID 845PxeBcSelectDhcp4Offer ( 846 IN PXEBC_PRIVATE_DATA *Private 847 ) 848{ 849 UINT32 Index; 850 UINT32 OfferIndex; 851 EFI_DHCP4_PACKET *Offer; 852 853 Private->SelectIndex = 0; 854 855 if (Private->IsOfferSorted) { 856 // 857 // Select offer by default policy. 858 // 859 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) { 860 // 861 // 1. DhcpPxe10 offer 862 // 863 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1; 864 865 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { 866 // 867 // 2. DhcpWfm11a offer 868 // 869 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1; 870 871 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 872 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { 873 // 874 // 3. DhcpOnly offer and ProxyPxe10 offer. 875 // 876 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 877 Private->SelectProxyType = PxeOfferTypeProxyPxe10; 878 879 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 880 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { 881 // 882 // 4. DhcpOnly offer and ProxyWfm11a offer. 883 // 884 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 885 Private->SelectProxyType = PxeOfferTypeProxyWfm11a; 886 887 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { 888 // 889 // 5. DhcpBinl offer. 890 // 891 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1; 892 893 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && 894 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { 895 // 896 // 6. DhcpOnly offer and ProxyBinl offer. 897 // 898 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; 899 Private->SelectProxyType = PxeOfferTypeProxyBinl; 900 901 } else { 902 // 903 // 7. DhcpOnly offer with bootfilename. 904 // 905 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) { 906 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index]; 907 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 908 Private->SelectIndex = OfferIndex + 1; 909 break; 910 } 911 } 912 // 913 // 8. Bootp offer with bootfilename. 914 // 915 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0]; 916 if (Private->SelectIndex == 0 && 917 Private->OfferCount[PxeOfferTypeBootp] > 0 && 918 Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) { 919 Private->SelectIndex = OfferIndex + 1; 920 } 921 } 922 } else { 923 // 924 // Select offer by received order. 925 // 926 for (Index = 0; Index < Private->OfferNum; Index++) { 927 928 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 929 930 if (IS_PROXY_DHCP_OFFER (Offer)) { 931 // 932 // Skip proxy offers 933 // 934 continue; 935 } 936 937 if (!Private->IsProxyRecved && 938 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly && 939 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 940 // 941 // Skip if DhcpOnly offer without any other proxy offers or bootfilename. 942 // 943 continue; 944 } 945 946 // 947 // Record the index of the select offer. 948 // 949 Private->SelectIndex = Index + 1; 950 break; 951 } 952 } 953} 954 955 956/** 957 Handle the DHCPv4 offer packet. 958 959 @param[in] Private Pointer to PxeBc private data. 960 961 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully. 962 @retval EFI_NO_RESPONSE No response to the following request packet. 963 @retval EFI_NOT_FOUND No boot filename received. 964 965**/ 966EFI_STATUS 967PxeBcHandleDhcp4Offer ( 968 IN PXEBC_PRIVATE_DATA *Private 969 ) 970{ 971 PXEBC_DHCP4_PACKET_CACHE *Cache4; 972 EFI_DHCP4_PACKET_OPTION **Options; 973 UINT32 Index; 974 EFI_DHCP4_PACKET *Offer; 975 PXEBC_OFFER_TYPE OfferType; 976 UINT32 ProxyIndex; 977 UINT32 SelectIndex; 978 EFI_STATUS Status; 979 EFI_PXE_BASE_CODE_MODE *Mode; 980 EFI_DHCP4_PACKET *Ack; 981 982 ASSERT (Private->SelectIndex > 0); 983 SelectIndex = (UINT32) (Private->SelectIndex - 1); 984 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); 985 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4; 986 Options = Cache4->OptList; 987 Status = EFI_SUCCESS; 988 989 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) { 990 // 991 // DhcpBinl offer is selected, so need try to request bootfilename by this offer. 992 // 993 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) { 994 Status = EFI_NO_RESPONSE; 995 } 996 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) { 997 998 if (Private->IsProxyRecved) { 999 // 1000 // DhcpOnly offer is selected, so need try to request bootfile name. 1001 // 1002 ProxyIndex = 0; 1003 if (Private->IsOfferSorted) { 1004 // 1005 // The proxy offer should be determined if select by default policy. 1006 // IsOfferSorted means all offers are labeled by OfferIndex. 1007 // 1008 ASSERT (Private->SelectProxyType < PxeOfferTypeMax); 1009 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0); 1010 1011 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) { 1012 // 1013 // Try all the cached ProxyBinl offer one by one to request bootfile name. 1014 // 1015 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) { 1016 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 1017 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index]; 1018 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) { 1019 break; 1020 } 1021 } 1022 if (Index == Private->OfferCount[Private->SelectProxyType]) { 1023 Status = EFI_NO_RESPONSE; 1024 } 1025 } else { 1026 // 1027 // For other proxy offers, only one is buffered. 1028 // 1029 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0]; 1030 } 1031 } else { 1032 // 1033 // The proxy offer should not be determined if select by received order. 1034 // 1035 Status = EFI_NO_RESPONSE; 1036 1037 for (Index = 0; Index < Private->OfferNum; Index++) { 1038 ASSERT (Index < PXEBC_OFFER_MAX_NUM); 1039 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; 1040 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType; 1041 if (!IS_PROXY_DHCP_OFFER (Offer)) { 1042 // 1043 // Skip non proxy DHCPv4 offers. 1044 // 1045 continue; 1046 } 1047 1048 if (OfferType == PxeOfferTypeProxyBinl) { 1049 // 1050 // Try all the cached ProxyBinl offer one by one to request bootfile name. 1051 // 1052 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) { 1053 continue; 1054 } 1055 } 1056 1057 Private->SelectProxyType = OfferType; 1058 ProxyIndex = Index; 1059 Status = EFI_SUCCESS; 1060 break; 1061 } 1062 } 1063 1064 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) { 1065 // 1066 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it. 1067 // 1068 PxeBcCopyProxyOffer (Private, ProxyIndex); 1069 } 1070 } else { 1071 // 1072 // Othewise, the bootfile name must be included in DhcpOnly offer. 1073 // 1074 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) { 1075 Status = EFI_NOT_FOUND; 1076 } 1077 } 1078 } 1079 1080 if (!EFI_ERROR (Status)) { 1081 // 1082 // All PXE boot information is ready by now. 1083 // 1084 Mode = Private->PxeBc.Mode; 1085 Offer = &Cache4->Packet.Offer; 1086 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack; 1087 if (Cache4->OfferType == PxeOfferTypeBootp) { 1088 // 1089 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply 1090 // should be taken as ack. 1091 // 1092 Ack = Offer; 1093 } 1094 1095 PxeBcCopyDhcp4Ack (Private, Ack, TRUE); 1096 Mode->DhcpDiscoverValid = TRUE; 1097 } 1098 1099 return Status; 1100} 1101 1102 1103/** 1104 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver 1105 to intercept events that occurred in the configuration process. 1106 1107 @param[in] This Pointer to the EFI DHCPv4 Protocol. 1108 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure(). 1109 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver. 1110 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a 1111 state transition. 1112 @param[in] Packet The DHCPv4 packet that is going to be sent or already received. 1113 @param[out] NewPacket The packet that is used to replace the above Packet. 1114 1115 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process. 1116 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol 1117 driver will continue to wait for more DHCPOFFER packets until the 1118 retry timeout expires. 1119 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process 1120 and return to the Dhcp4Init or Dhcp4InitReboot state. 1121 1122**/ 1123EFI_STATUS 1124EFIAPI 1125PxeBcDhcp4CallBack ( 1126 IN EFI_DHCP4_PROTOCOL *This, 1127 IN VOID *Context, 1128 IN EFI_DHCP4_STATE CurrentState, 1129 IN EFI_DHCP4_EVENT Dhcp4Event, 1130 IN EFI_DHCP4_PACKET *Packet OPTIONAL, 1131 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL 1132 ) 1133{ 1134 PXEBC_PRIVATE_DATA *Private; 1135 EFI_PXE_BASE_CODE_MODE *Mode; 1136 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; 1137 EFI_DHCP4_PACKET_OPTION *MaxMsgSize; 1138 UINT16 Value; 1139 EFI_STATUS Status; 1140 BOOLEAN Received; 1141 1142 if ((Dhcp4Event != Dhcp4RcvdOffer) && 1143 (Dhcp4Event != Dhcp4SelectOffer) && 1144 (Dhcp4Event != Dhcp4SendDiscover) && 1145 (Dhcp4Event != Dhcp4RcvdAck)) { 1146 return EFI_SUCCESS; 1147 } 1148 1149 Private = (PXEBC_PRIVATE_DATA *) Context; 1150 Mode = Private->PxeBc.Mode; 1151 Callback = Private->PxeBcCallback; 1152 1153 // 1154 // Override the Maximum DHCP Message Size. 1155 // 1156 MaxMsgSize = PxeBcParseDhcp4Options ( 1157 Packet->Dhcp4.Option, 1158 GET_OPTION_BUFFER_LEN (Packet), 1159 PXEBC_DHCP4_TAG_MAXMSG 1160 ); 1161 if (MaxMsgSize != NULL) { 1162 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8); 1163 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value)); 1164 } 1165 1166 // 1167 // Callback to user if any packets sent or received. 1168 // 1169 if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) { 1170 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck); 1171 Status = Callback->Callback ( 1172 Callback, 1173 Private->Function, 1174 Received, 1175 Packet->Length, 1176 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4 1177 ); 1178 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { 1179 return EFI_ABORTED; 1180 } 1181 } 1182 1183 Status = EFI_SUCCESS; 1184 1185 switch (Dhcp4Event) { 1186 1187 case Dhcp4SendDiscover: 1188 // 1189 // Cache the DHCPv4 discover packet to mode data directly. 1190 // It need to check SendGuid as well as Dhcp4SendRequest. 1191 // 1192 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length); 1193 1194 case Dhcp4SendRequest: 1195 if (Mode->SendGUID) { 1196 // 1197 // Send the system Guid instead of the MAC address as the hardware address if required. 1198 // 1199 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) { 1200 // 1201 // Zero the Guid to indicate NOT programable if failed to get system Guid. 1202 // 1203 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID)); 1204 } 1205 Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID); 1206 } 1207 break; 1208 1209 case Dhcp4RcvdOffer: 1210 Status = EFI_NOT_READY; 1211 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { 1212 // 1213 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record 1214 // the OfferIndex and OfferCount. 1215 // 1216 PxeBcCacheDhcp4Offer (Private, Packet); 1217 } 1218 break; 1219 1220 case Dhcp4SelectOffer: 1221 // 1222 // Select offer by the default policy or by order, and record the SelectIndex 1223 // and SelectProxyType. 1224 // 1225 PxeBcSelectDhcp4Offer (Private); 1226 1227 if (Private->SelectIndex == 0) { 1228 Status = EFI_ABORTED; 1229 } else { 1230 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer; 1231 } 1232 break; 1233 1234 case Dhcp4RcvdAck: 1235 // 1236 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data 1237 // without verification. 1238 // 1239 ASSERT (Private->SelectIndex != 0); 1240 1241 PxeBcCopyDhcp4Ack (Private, Packet, FALSE); 1242 break; 1243 1244 default: 1245 break; 1246 } 1247 1248 return Status; 1249} 1250 1251 1252/** 1253 Build and send out the request packet for the bootfile, and parse the reply. 1254 1255 @param[in] Private Pointer to PxeBc private data. 1256 @param[in] Type PxeBc option boot item type. 1257 @param[in] Layer Pointer to option boot item layer. 1258 @param[in] UseBis Use BIS or not. 1259 @param[in] DestIp Pointer to the server address. 1260 @param[in] IpCount The total count of the server address. 1261 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. 1262 1263 @retval EFI_SUCCESS Successfully discovered boot file. 1264 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. 1265 @retval EFI_NOT_FOUND Can't get the PXE reply packet. 1266 @retval Others Failed to discover boot file. 1267 1268**/ 1269EFI_STATUS 1270PxeBcDhcp4Discover ( 1271 IN PXEBC_PRIVATE_DATA *Private, 1272 IN UINT16 Type, 1273 IN UINT16 *Layer, 1274 IN BOOLEAN UseBis, 1275 IN EFI_IP_ADDRESS *DestIp, 1276 IN UINT16 IpCount, 1277 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList 1278 ) 1279{ 1280 EFI_PXE_BASE_CODE_UDP_PORT Sport; 1281 EFI_PXE_BASE_CODE_MODE *Mode; 1282 EFI_DHCP4_PROTOCOL *Dhcp4; 1283 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; 1284 BOOLEAN IsBCast; 1285 EFI_STATUS Status; 1286 UINT16 RepIndex; 1287 UINT16 SrvIndex; 1288 UINT16 TryIndex; 1289 EFI_DHCP4_LISTEN_POINT ListenPoint; 1290 EFI_DHCP4_PACKET *Response; 1291 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; 1292 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; 1293 UINT32 OptCount; 1294 EFI_DHCP4_PACKET_OPTION *PxeOpt; 1295 PXEBC_OPTION_BOOT_ITEM *PxeBootItem; 1296 UINT8 VendorOptLen; 1297 UINT32 Xid; 1298 1299 Mode = Private->PxeBc.Mode; 1300 Dhcp4 = Private->Dhcp4; 1301 Status = EFI_SUCCESS; 1302 1303 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN)); 1304 1305 // 1306 // Use broadcast if destination address not specified. 1307 // 1308 if (DestIp == NULL) { 1309 Sport = PXEBC_DHCP4_S_PORT; 1310 IsBCast = TRUE; 1311 } else { 1312 Sport = PXEBC_BS_DISCOVER_PORT; 1313 IsBCast = FALSE; 1314 } 1315 1316 if (!UseBis && Layer != NULL) { 1317 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; 1318 } 1319 1320 // 1321 // Build all the options for the request packet. 1322 // 1323 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE); 1324 1325 if (Private->IsDoDiscover) { 1326 // 1327 // Add vendor option of PXE_BOOT_ITEM 1328 // 1329 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1); 1330 OptList[OptCount] = AllocateZeroPool (VendorOptLen); 1331 if (OptList[OptCount] == NULL) { 1332 return EFI_OUT_OF_RESOURCES; 1333 } 1334 1335 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR; 1336 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2); 1337 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data; 1338 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM; 1339 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM); 1340 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data; 1341 PxeBootItem->Type = HTONS (Type); 1342 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP; 1343 1344 if (Layer != NULL) { 1345 PxeBootItem->Layer = HTONS (*Layer); 1346 } 1347 1348 OptCount++; 1349 } 1350 1351 // 1352 // Build the request packet with seed packet and option list. 1353 // 1354 Status = Dhcp4->Build ( 1355 Dhcp4, 1356 &Private->SeedPacket, 1357 0, 1358 NULL, 1359 OptCount, 1360 OptList, 1361 &Token.Packet 1362 ); 1363 // 1364 // Free the vendor option of PXE_BOOT_ITEM. 1365 // 1366 if (Private->IsDoDiscover) { 1367 FreePool (OptList[OptCount - 1]); 1368 } 1369 1370 if (EFI_ERROR (Status)) { 1371 return Status; 1372 } 1373 1374 if (Mode->SendGUID) { 1375 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) { 1376 // 1377 // Zero the Guid to indicate NOT programable if failed to get system Guid. 1378 // 1379 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID)); 1380 } 1381 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID); 1382 } 1383 1384 // 1385 // Set fields of the token for the request packet. 1386 // 1387 Xid = NET_RANDOM (NetRandomInitSeed ()); 1388 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid); 1389 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0)); 1390 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); 1391 1392 Token.RemotePort = Sport; 1393 1394 if (IsBCast) { 1395 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff); 1396 } else { 1397 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS)); 1398 } 1399 1400 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS)); 1401 1402 if (!IsBCast) { 1403 Token.ListenPointCount = 1; 1404 Token.ListenPoints = &ListenPoint; 1405 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT; 1406 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS)); 1407 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS)); 1408 } 1409 1410 // 1411 // Send out the request packet to discover the bootfile. 1412 // 1413 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) { 1414 1415 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex); 1416 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1)); 1417 1418 Status = Dhcp4->TransmitReceive (Dhcp4, &Token); 1419 if (Token.Status != EFI_TIMEOUT) { 1420 break; 1421 } 1422 } 1423 1424 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) { 1425 // 1426 // No server response our PXE request 1427 // 1428 Status = EFI_TIMEOUT; 1429 } 1430 1431 if (!EFI_ERROR (Status)) { 1432 1433 RepIndex = 0; 1434 SrvIndex = 0; 1435 Response = Token.ResponseList; 1436 // 1437 // Find the right PXE Reply according to server address. 1438 // 1439 while (RepIndex < Token.ResponseCount) { 1440 1441 while (SrvIndex < IpCount) { 1442 if (SrvList[SrvIndex].AcceptAnyResponse) { 1443 break; 1444 } 1445 if ((SrvList[SrvIndex].Type == Type) && 1446 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) { 1447 break; 1448 } 1449 SrvIndex++; 1450 } 1451 1452 if ((IpCount != SrvIndex) || (IpCount == 0)) { 1453 break; 1454 } 1455 1456 SrvIndex = 0; 1457 RepIndex++; 1458 1459 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size); 1460 } 1461 1462 if (RepIndex < Token.ResponseCount) { 1463 // 1464 // Cache the right PXE reply packet here, set valid flag later. 1465 // Especially for PXE discover packet, store it into mode data here. 1466 // 1467 if (Private->IsDoDiscover) { 1468 PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response); 1469 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length); 1470 } else { 1471 PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response); 1472 } 1473 } else { 1474 // 1475 // Not found the right PXE reply packet. 1476 // 1477 Status = EFI_NOT_FOUND; 1478 } 1479 if (Token.ResponseList != NULL) { 1480 FreePool (Token.ResponseList); 1481 } 1482 } 1483 1484 FreePool (Token.Packet); 1485 return Status; 1486} 1487 1488 1489/** 1490 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information. 1491 1492 @param[in] Private Pointer to PxeBc private data. 1493 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL 1494 1495 @retval EFI_SUCCESS The D.O.R.A process successfully finished. 1496 @retval Others Failed to finish the D.O.R.A process. 1497 1498**/ 1499EFI_STATUS 1500PxeBcDhcp4Dora ( 1501 IN PXEBC_PRIVATE_DATA *Private, 1502 IN EFI_DHCP4_PROTOCOL *Dhcp4 1503 ) 1504{ 1505 EFI_PXE_BASE_CODE_MODE *PxeMode; 1506 EFI_DHCP4_CONFIG_DATA Config; 1507 EFI_DHCP4_MODE_DATA Mode; 1508 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; 1509 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; 1510 UINT32 OptCount; 1511 EFI_STATUS Status; 1512 1513 ASSERT (Dhcp4 != NULL); 1514 1515 Status = EFI_SUCCESS; 1516 PxeMode = Private->PxeBc.Mode; 1517 1518 // 1519 // Build option list for the request packet. 1520 // 1521 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE); 1522 ASSERT (OptCount> 0); 1523 1524 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA)); 1525 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1526 1527 Config.OptionCount = OptCount; 1528 Config.OptionList = OptList; 1529 Config.Dhcp4Callback = PxeBcDhcp4CallBack; 1530 Config.CallbackContext = Private; 1531 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES; 1532 Config.DiscoverTimeout = mPxeDhcpTimeout; 1533 1534 // 1535 // Configure the DHCPv4 instance for PXE boot. 1536 // 1537 Status = Dhcp4->Configure (Dhcp4, &Config); 1538 if (EFI_ERROR (Status)) { 1539 goto ON_EXIT; 1540 } 1541 1542 // 1543 // Initialize the record fields for DHCPv4 offer in private data. 1544 // 1545 Private->IsProxyRecved = FALSE; 1546 Private->OfferNum = 0; 1547 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 1548 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 1549 1550 // 1551 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. 1552 // 1553 Status = Dhcp4->Start (Dhcp4, NULL); 1554 if (EFI_ERROR (Status)) { 1555 if (Status == EFI_ICMP_ERROR) { 1556 PxeMode->IcmpErrorReceived = TRUE; 1557 } 1558 goto ON_EXIT; 1559 } 1560 1561 // 1562 // Get the acquired IPv4 address and store them. 1563 // 1564 Status = Dhcp4->GetModeData (Dhcp4, &Mode); 1565 if (EFI_ERROR (Status)) { 1566 goto ON_EXIT; 1567 } 1568 1569 ASSERT (Mode.State == Dhcp4Bound); 1570 1571 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); 1572 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1573 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 1574 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); 1575 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1576 1577 Status = PxeBcFlushStaionIp (Private, &Private->StationIp, &Private->SubnetMask); 1578 if (EFI_ERROR (Status)) { 1579 goto ON_EXIT; 1580 } 1581 1582 // 1583 // Check the selected offer whether BINL retry is needed. 1584 // 1585 Status = PxeBcHandleDhcp4Offer (Private); 1586 1587 AsciiPrint ("\n Station IP address is "); 1588 1589 PxeBcShowIp4Addr (&Private->StationIp.v4); 1590 AsciiPrint ("\n"); 1591 1592ON_EXIT: 1593 if (EFI_ERROR (Status)) { 1594 Dhcp4->Stop (Dhcp4); 1595 Dhcp4->Configure (Dhcp4, NULL); 1596 } else { 1597 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1598 Dhcp4->Configure (Dhcp4, &Config); 1599 Private->IsAddressOk = TRUE; 1600 } 1601 1602 return Status; 1603} 1604