1 /** @file 2 Functions implementation related with DHCPv4 for UefiPxeBc Driver. 3 4 Copyright (c) 2009 - 2015, 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 // 21 UINT8 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 // 34 UINT32 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 **/ 48 EFI_DHCP4_PACKET_OPTION * 49 PxeBcParseDhcp4Options ( 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 **/ 93 VOID 94 PxeBcParseVendorOptions ( 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 **/ 227 UINT32 228 PxeBcBuildDhcp4Options ( 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 **/ 393 VOID 394 PxeBcSeedDhcp4Packet ( 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 **/ 428 VOID 429 PxeBcCacheDhcp4Packet ( 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 **/ 450 EFI_STATUS 451 PxeBcParseDhcp4Packet ( 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 zero "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 **/ 621 VOID 622 PxeBcCopyDhcp4Ack ( 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 **/ 652 VOID 653 PxeBcCopyProxyOffer ( 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 **/ 691 EFI_STATUS 692 PxeBcRetryBinlOffer ( 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 **/ 781 VOID 782 PxeBcCacheDhcp4Offer ( 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 **/ 865 VOID 866 PxeBcSelectDhcp4Offer ( 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 **/ 987 EFI_STATUS 988 PxeBcHandleDhcp4Offer ( 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 **/ 1144 EFI_STATUS 1145 EFIAPI 1146 PxeBcDhcp4CallBack ( 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 **/ 1290 EFI_STATUS 1291 PxeBcDhcp4Discover ( 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 Switch the Ip4 policy to static. 1511 1512 @param[in] Private The pointer to PXEBC_PRIVATE_DATA. 1513 1514 @retval EFI_SUCCESS The policy is already configured to static. 1515 @retval Others Other error as indicated.. 1516 1517 **/ 1518 EFI_STATUS 1519 PxeBcSetIp4Policy ( 1520 IN PXEBC_PRIVATE_DATA *Private 1521 ) 1522 { 1523 EFI_STATUS Status; 1524 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; 1525 EFI_IP4_CONFIG2_POLICY Policy; 1526 UINTN DataSize; 1527 1528 Ip4Config2 = Private->Ip4Config2; 1529 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY); 1530 Status = Ip4Config2->GetData ( 1531 Ip4Config2, 1532 Ip4Config2DataTypePolicy, 1533 &DataSize, 1534 &Policy 1535 ); 1536 if (EFI_ERROR (Status)) { 1537 return Status; 1538 } 1539 1540 if (Policy != Ip4Config2PolicyStatic) { 1541 Policy = Ip4Config2PolicyStatic; 1542 Status= Ip4Config2->SetData ( 1543 Ip4Config2, 1544 Ip4Config2DataTypePolicy, 1545 sizeof (EFI_IP4_CONFIG2_POLICY), 1546 &Policy 1547 ); 1548 if (EFI_ERROR (Status)) { 1549 return Status; 1550 } 1551 } 1552 1553 return EFI_SUCCESS; 1554 } 1555 1556 /** 1557 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information. 1558 1559 @param[in] Private Pointer to PxeBc private data. 1560 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL 1561 1562 @retval EFI_SUCCESS The D.O.R.A process successfully finished. 1563 @retval Others Failed to finish the D.O.R.A process. 1564 1565 **/ 1566 EFI_STATUS 1567 PxeBcDhcp4Dora ( 1568 IN PXEBC_PRIVATE_DATA *Private, 1569 IN EFI_DHCP4_PROTOCOL *Dhcp4 1570 ) 1571 { 1572 EFI_PXE_BASE_CODE_MODE *PxeMode; 1573 EFI_DHCP4_CONFIG_DATA Config; 1574 EFI_DHCP4_MODE_DATA Mode; 1575 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; 1576 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; 1577 UINT32 OptCount; 1578 EFI_STATUS Status; 1579 1580 ASSERT (Dhcp4 != NULL); 1581 1582 Status = EFI_SUCCESS; 1583 PxeMode = Private->PxeBc.Mode; 1584 1585 // 1586 // Build option list for the request packet. 1587 // 1588 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE); 1589 ASSERT (OptCount> 0); 1590 1591 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA)); 1592 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1593 1594 Config.OptionCount = OptCount; 1595 Config.OptionList = OptList; 1596 Config.Dhcp4Callback = PxeBcDhcp4CallBack; 1597 Config.CallbackContext = Private; 1598 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES; 1599 Config.DiscoverTimeout = mPxeDhcpTimeout; 1600 1601 // 1602 // Configure the DHCPv4 instance for PXE boot. 1603 // 1604 Status = Dhcp4->Configure (Dhcp4, &Config); 1605 if (EFI_ERROR (Status)) { 1606 goto ON_EXIT; 1607 } 1608 1609 // 1610 // Initialize the record fields for DHCPv4 offer in private data. 1611 // 1612 Private->IsProxyRecved = FALSE; 1613 Private->OfferNum = 0; 1614 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); 1615 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); 1616 1617 // 1618 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. This may 1619 // have already been done, thus do not leave in error if the return 1620 // code is EFI_ALREADY_STARTED. 1621 // 1622 Status = Dhcp4->Start (Dhcp4, NULL); 1623 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 1624 if (Status == EFI_ICMP_ERROR) { 1625 PxeMode->IcmpErrorReceived = TRUE; 1626 } 1627 goto ON_EXIT; 1628 } 1629 1630 // 1631 // Get the acquired IPv4 address and store them. 1632 // 1633 Status = Dhcp4->GetModeData (Dhcp4, &Mode); 1634 if (EFI_ERROR (Status)) { 1635 goto ON_EXIT; 1636 } 1637 1638 ASSERT (Mode.State == Dhcp4Bound); 1639 1640 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); 1641 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1642 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 1643 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); 1644 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1645 1646 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask); 1647 if (EFI_ERROR (Status)) { 1648 goto ON_EXIT; 1649 } 1650 1651 // 1652 // Check the selected offer whether BINL retry is needed. 1653 // 1654 Status = PxeBcHandleDhcp4Offer (Private); 1655 1656 AsciiPrint ("\n Station IP address is "); 1657 1658 PxeBcShowIp4Addr (&Private->StationIp.v4); 1659 AsciiPrint ("\n"); 1660 1661 ON_EXIT: 1662 if (EFI_ERROR (Status)) { 1663 Dhcp4->Stop (Dhcp4); 1664 Dhcp4->Configure (Dhcp4, NULL); 1665 } else { 1666 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 1667 Dhcp4->Configure (Dhcp4, &Config); 1668 Private->IsAddressOk = TRUE; 1669 } 1670 1671 return Status; 1672 } 1673