TianoCore EDK2 master
Loading...
Searching...
No Matches
PxeBcDhcp4.c
Go to the documentation of this file.
1
10#include "PxeBcImpl.h"
11
12//
13// This is a map from the interested DHCP4 option tags' index to the tag value.
14//
15UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
16 DHCP4_TAG_BOOTFILE_LEN,
17 DHCP4_TAG_VENDOR,
18 DHCP4_TAG_OVERLOAD,
19 DHCP4_TAG_MSG_TYPE,
20 DHCP4_TAG_SERVER_ID,
21 DHCP4_TAG_VENDOR_CLASS_ID,
22 DHCP4_TAG_BOOTFILE
23};
24
25//
26// There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
27//
28UINT32 mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
29
43 IN UINT8 *Buffer,
44 IN UINT32 Length,
45 IN UINT8 OptTag
46 )
47{
49 UINT32 Offset;
50
51 Option = (EFI_DHCP4_PACKET_OPTION *)Buffer;
52 Offset = 0;
53
54 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {
55 if (Option->OpCode == OptTag) {
56 //
57 // Found the required option.
58 //
59 return Option;
60 }
61
62 //
63 // Skip the current option to the next.
64 //
65 if (Option->OpCode == DHCP4_TAG_PAD) {
66 Offset++;
67 } else {
68 Offset += Option->Length + 2;
69 }
70
71 Option = (EFI_DHCP4_PACKET_OPTION *)(Buffer + Offset);
72 }
73
74 return NULL;
75}
76
84VOID
86 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,
87 IN PXEBC_VENDOR_OPTION *VendorOption
88 )
89{
90 UINT32 *BitMap;
91 UINT8 VendorOptionLen;
92 EFI_DHCP4_PACKET_OPTION *PxeOption;
93 UINT8 Offset;
94
95 BitMap = VendorOption->BitMap;
96 VendorOptionLen = Dhcp4Option->Length;
97 PxeOption = (EFI_DHCP4_PACKET_OPTION *)&Dhcp4Option->Data[0];
98 Offset = 0;
99
100 ASSERT (PxeOption != NULL);
101
102 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != DHCP4_TAG_EOP)) {
103 //
104 // Parse all the interesting PXE vendor options one by one.
105 //
106 switch (PxeOption->OpCode) {
107 case PXEBC_VENDOR_TAG_MTFTP_IP:
108
109 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
110 break;
111
112 case PXEBC_VENDOR_TAG_MTFTP_CPORT:
113
114 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
115 break;
116
117 case PXEBC_VENDOR_TAG_MTFTP_SPORT:
118
119 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
120 break;
121
122 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
123
124 VendorOption->MtftpTimeout = *PxeOption->Data;
125 break;
126
127 case PXEBC_VENDOR_TAG_MTFTP_DELAY:
128
129 VendorOption->MtftpDelay = *PxeOption->Data;
130 break;
131
132 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
133
134 VendorOption->DiscoverCtrl = *PxeOption->Data;
135 break;
136
137 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
138
139 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
140 break;
141
142 case PXEBC_VENDOR_TAG_BOOT_SERVERS:
143
144 VendorOption->BootSvrLen = PxeOption->Length;
145 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *)PxeOption->Data;
146 break;
147
148 case PXEBC_VENDOR_TAG_BOOT_MENU:
149
150 VendorOption->BootMenuLen = PxeOption->Length;
151 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *)PxeOption->Data;
152 break;
153
154 case PXEBC_VENDOR_TAG_MENU_PROMPT:
155
156 VendorOption->MenuPromptLen = PxeOption->Length;
157 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *)PxeOption->Data;
158 break;
159
160 case PXEBC_VENDOR_TAG_MCAST_ALLOC:
161
162 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
163 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
164 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
165 break;
166
167 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
168
169 VendorOption->CredTypeLen = PxeOption->Length;
170 VendorOption->CredType = (UINT32 *)PxeOption->Data;
171 break;
172
173 case PXEBC_VENDOR_TAG_BOOT_ITEM:
174
175 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
176 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
177 break;
178
179 default:
180 //
181 // Not interesting PXE vendor options.
182 //
183 break;
184 }
185
186 //
187 // Set the bit map for the special PXE options.
188 //
189 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
190
191 //
192 // Continue to the next option.
193 //
194 if (PxeOption->OpCode == DHCP4_TAG_PAD) {
195 Offset++;
196 } else {
197 Offset = (UINT8)(Offset + PxeOption->Length + 2);
198 }
199
200 PxeOption = (EFI_DHCP4_PACKET_OPTION *)(Dhcp4Option->Data + Offset);
201 }
202}
203
216UINT32
218 IN PXEBC_PRIVATE_DATA *Private,
220 IN UINT8 *Buffer,
221 IN BOOLEAN NeedMsgType
222 )
223{
224 UINT32 Index;
226 UINT16 Value;
227
228 Index = 0;
229 OptList[0] = (EFI_DHCP4_PACKET_OPTION *)Buffer;
230
231 if (NeedMsgType) {
232 //
233 // Append message type.
234 //
235 OptList[Index]->OpCode = DHCP4_TAG_MSG_TYPE;
236 OptList[Index]->Length = 1;
237 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *)OptList[Index]->Data;
238 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;
239 Index++;
240 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
241
242 //
243 // Append max message size.
244 //
245 OptList[Index]->OpCode = DHCP4_TAG_MAXMSG;
246 OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
247 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *)OptList[Index]->Data;
248 Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE);
249 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
250 Index++;
251 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
252 }
253
254 //
255 // Append parameter request list option.
256 //
257 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;
258 OptList[Index]->Length = 35;
259 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *)OptList[Index]->Data;
260 OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;
261 OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;
262 OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;
263 OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;
264 OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;
265 OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;
266 OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;
267 OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;
268 OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;
269 OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;
270 OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;
271 OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;
272 OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;
273 OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;
274 OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;
275 OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;
276 OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;
277 OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;
278 OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;
279 OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;
280 OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;
281 OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;
282 OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;
283 OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;
284 OptEnt.Para->ParaList[24] = DHCP4_TAG_TFTP;
285 OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;
286 OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;
287 OptEnt.Para->ParaList[27] = 0x80;
288 OptEnt.Para->ParaList[28] = 0x81;
289 OptEnt.Para->ParaList[29] = 0x82;
290 OptEnt.Para->ParaList[30] = 0x83;
291 OptEnt.Para->ParaList[31] = 0x84;
292 OptEnt.Para->ParaList[32] = 0x85;
293 OptEnt.Para->ParaList[33] = 0x86;
294 OptEnt.Para->ParaList[34] = 0x87;
295 Index++;
296 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
297
298 //
299 // Append UUID/Guid-based client identifier option
300 //
301 OptList[Index]->OpCode = DHCP4_TAG_UUID;
302 OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_UUID);
303 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *)OptList[Index]->Data;
304 OptEnt.Uuid->Type = 0;
305 Index++;
306 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
307
308 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)OptEnt.Uuid->Guid))) {
309 //
310 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
311 //
312 DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
313 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
314 }
315
316 //
317 // Append client network device interface option
318 //
319 OptList[Index]->OpCode = DHCP4_TAG_UNDI;
320 OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_UNDI);
321 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *)OptList[Index]->Data;
322
323 if (Private->Nii != NULL) {
324 OptEnt.Undi->Type = Private->Nii->Type;
325 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
326 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
327 } else {
328 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
329 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
330 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
331 }
332
333 Index++;
334 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
335
336 //
337 // Append client system architecture option
338 //
339 OptList[Index]->OpCode = DHCP4_TAG_ARCH;
340 OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_ARCH);
341 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *)OptList[Index]->Data;
342 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
343 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
344 Index++;
345 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
346
347 //
348 // Append vendor class identify option
349 //
350 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;
351 OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_CLID);
352 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *)OptList[Index]->Data;
353 CopyMem (
354 OptEnt.Clid,
355 DEFAULT_CLASS_ID_DATA,
357 );
359 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
360 OptEnt.Clid->ArchitectureType,
361 sizeof (OptEnt.Clid->ArchitectureType)
362 );
363
364 if (Private->Nii != NULL) {
365 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
366 PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
367 PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
368 }
369
370 Index++;
371
372 return Index;
373}
374
382VOID
384 OUT EFI_DHCP4_PACKET *Seed,
386 )
387{
389 EFI_DHCP4_HEADER *Header;
390
391 //
392 // Get IfType and HwAddressSize from SNP mode data.
393 //
394 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
395
396 Seed->Size = sizeof (EFI_DHCP4_PACKET);
397 Seed->Length = sizeof (Seed->Dhcp4);
398 Header = &Seed->Dhcp4.Header;
399 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
400 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;
401 Header->HwType = Mode.IfType;
402 Header->HwAddrLen = (UINT8)Mode.HwAddressSize;
403 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
404
405 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;
406 Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
407}
408
421 IN EFI_DHCP4_PACKET *Dst,
423 )
424{
425 if (Dst->Size < Src->Length) {
426 return EFI_BUFFER_TOO_SMALL;
427 }
428
429 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
430 Dst->Length = Src->Length;
431
432 return EFI_SUCCESS;
433}
434
447 )
448{
449 EFI_DHCP4_PACKET *Offer;
450 EFI_DHCP4_PACKET_OPTION **Options;
452 PXEBC_OFFER_TYPE OfferType;
453 UINTN Index;
454 BOOLEAN IsProxyOffer;
455 BOOLEAN IsPxeOffer;
456 UINT8 *Ptr8;
457 BOOLEAN FileFieldOverloaded;
458
459 IsProxyOffer = FALSE;
460 IsPxeOffer = FALSE;
461 FileFieldOverloaded = FALSE;
462
463 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
464 ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));
465
466 Offer = &Cache4->Packet.Offer;
467 Options = Cache4->OptList;
468
469 //
470 // Parse DHCPv4 options in this offer, and store the pointers.
471 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
472 //
473 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
474 Options[Index] = PxeBcParseDhcp4Options (
475 Offer->Dhcp4.Option,
476 GET_OPTION_BUFFER_LEN (Offer),
477 mInterestedDhcp4Tags[Index]
478 );
479 }
480
481 //
482 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
483 // If yes, try to parse options from the BootFileName field, then ServerName field.
484 //
485 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
486 if (Option != NULL) {
487 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
488 FileFieldOverloaded = TRUE;
489 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
490 if (Options[Index] == NULL) {
491 Options[Index] = PxeBcParseDhcp4Options (
492 (UINT8 *)Offer->Dhcp4.Header.BootFileName,
493 sizeof (Offer->Dhcp4.Header.BootFileName),
494 mInterestedDhcp4Tags[Index]
495 );
496 }
497 }
498 }
499
500 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
501 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
502 if (Options[Index] == NULL) {
503 Options[Index] = PxeBcParseDhcp4Options (
504 (UINT8 *)Offer->Dhcp4.Header.ServerName,
505 sizeof (Offer->Dhcp4.Header.ServerName),
506 mInterestedDhcp4Tags[Index]
507 );
508 }
509 }
510 }
511 }
512
513 //
514 // The offer with zero "yiaddr" is a proxy offer.
515 //
516 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
517 IsProxyOffer = TRUE;
518 }
519
520 //
521 // The offer with "PXEClient" is a PXE offer.
522 //
523 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
524 if ((Option != NULL) && (Option->Length >= 9) &&
525 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0))
526 {
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 (!FileFieldOverloaded && (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] -
561 }
562
563 //
564 // Determine offer type of the DHCPv4 packet.
565 //
566 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
567 if ((Option == NULL) || (Option->Data[0] == 0)) {
568 //
569 // It's a Bootp offer.
570 //
571 OfferType = PxeOfferTypeBootp;
572
573 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
574 if (Option == NULL) {
575 //
576 // If the Bootp offer without bootfilename, discard it.
577 //
578 return EFI_DEVICE_ERROR;
579 }
580 } else {
581 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
582 //
583 // It's a PXE10 offer with PXEClient and discover vendor option.
584 //
585 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
586 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
587 //
588 // It's a WFM11a offer with PXEClient and mtftp vendor option.
589 // But multi-cast download is not supported currently, so discard it.
590 //
591 return EFI_DEVICE_ERROR;
592 } else if (IsPxeOffer) {
593 //
594 // It's a BINL offer only with PXEClient.
595 //
596 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
597 } else {
598 //
599 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
600 //
601 OfferType = PxeOfferTypeDhcpOnly;
602 }
603 }
604
605 Cache4->OfferType = OfferType;
606
607 return EFI_SUCCESS;
608}
609
623 IN PXEBC_PRIVATE_DATA *Private,
624 IN EFI_DHCP4_PACKET *Ack,
625 IN BOOLEAN Verified
626 )
627{
629 EFI_STATUS Status;
630
631 Mode = Private->PxeBc.Mode;
632
633 Status = PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
634 if (EFI_ERROR (Status)) {
635 return Status;
636 }
637
638 if (Verified) {
639 //
640 // Parse the ack packet and store it into mode data if needed.
641 //
642 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
643 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
644 Mode->DhcpAckReceived = TRUE;
645 }
646
647 return EFI_SUCCESS;
648}
649
662 IN PXEBC_PRIVATE_DATA *Private,
663 IN UINT32 OfferIndex
664 )
665{
667 EFI_DHCP4_PACKET *Offer;
668 EFI_STATUS Status;
669
670 ASSERT (OfferIndex < Private->OfferNum);
671 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
672
673 Mode = Private->PxeBc.Mode;
674 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
675
676 //
677 // Cache the proxy offer packet and parse it.
678 //
679 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
680 if (EFI_ERROR (Status)) {
681 return Status;
682 }
683
684 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
685
686 //
687 // Store this packet into mode data.
688 //
689 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
690 Mode->ProxyOfferReceived = TRUE;
691
692 return EFI_SUCCESS;
693}
694
707 IN PXEBC_PRIVATE_DATA *Private,
708 IN UINT32 Index
709 )
710{
711 EFI_DHCP4_PACKET *Offer;
712 EFI_IP_ADDRESS ServerIp;
713 EFI_STATUS Status;
715 EFI_DHCP4_PACKET *Reply;
716
717 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
718 ASSERT (
719 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
720 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl
721 );
722
723 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
724
725 //
726 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
727 //
728 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
729 CopyMem (
730 &ServerIp.Addr[0],
731 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
732 sizeof (EFI_IPv4_ADDRESS)
733 );
734 } else {
735 CopyMem (
736 &ServerIp.Addr[0],
737 &Offer->Dhcp4.Header.ServerAddr,
738 sizeof (EFI_IPv4_ADDRESS)
739 );
740 }
741
742 Private->IsDoDiscover = FALSE;
743 Cache4 = &Private->ProxyOffer.Dhcp4;
744 Reply = &Cache4->Packet.Offer;
745
746 //
747 // Send another request packet for bootfile name.
748 //
749 Status = PxeBcDhcp4Discover (
750 Private,
751 0,
752 NULL,
753 FALSE,
754 &ServerIp,
755 0,
756 NULL
757 );
758 if (EFI_ERROR (Status)) {
759 return Status;
760 }
761
762 //
763 // Parse the reply for the last request packet.
764 //
765 Status = PxeBcParseDhcp4Packet (Cache4);
766 if (EFI_ERROR (Status)) {
767 return Status;
768 }
769
770 if ((Cache4->OfferType != PxeOfferTypeProxyPxe10) &&
771 (Cache4->OfferType != PxeOfferTypeProxyWfm11a) &&
772 (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))
773 {
774 //
775 // This BINL ack doesn't have discovery option set or multicast option set
776 // or bootfile name specified.
777 //
778 return EFI_DEVICE_ERROR;
779 }
780
781 //
782 // Store the reply into mode data.
783 //
784 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
785 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
786
787 return EFI_SUCCESS;
788}
789
802 IN PXEBC_PRIVATE_DATA *Private,
803 IN EFI_DHCP4_PACKET *RcvdOffer
804 )
805{
807 EFI_DHCP4_PACKET *Offer;
808 PXEBC_OFFER_TYPE OfferType;
809 EFI_STATUS Status;
810
811 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
812 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
813 Offer = &Cache4->Packet.Offer;
814
815 //
816 // Cache the content of DHCPv4 packet firstly.
817 //
818 Status = PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
819 if (EFI_ERROR (Status)) {
820 return Status;
821 }
822
823 //
824 // Validate the DHCPv4 packet, and parse the options and offer type.
825 //
826 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
827 return EFI_ABORTED;
828 }
829
830 //
831 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
832 //
833 OfferType = Cache4->OfferType;
834 ASSERT (OfferType < PxeOfferTypeMax);
835
836 if (OfferType == PxeOfferTypeBootp) {
837 //
838 // It's a Bootp offer, only cache the first one, and discard the others.
839 //
840 if (Private->OfferCount[OfferType] == 0) {
841 Private->OfferIndex[OfferType][0] = Private->OfferNum;
842 Private->OfferCount[OfferType] = 1;
843 } else {
844 return EFI_ABORTED;
845 }
846 } else {
847 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
848 if (IS_PROXY_DHCP_OFFER (Offer)) {
849 //
850 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
851 //
852 Private->IsProxyRecved = TRUE;
853
854 if (OfferType == PxeOfferTypeProxyBinl) {
855 //
856 // Cache all proxy BINL offers.
857 //
858 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
859 Private->OfferCount[OfferType]++;
860 } else if (((OfferType == PxeOfferTypeProxyPxe10) || (OfferType == PxeOfferTypeProxyWfm11a)) &&
861 (Private->OfferCount[OfferType] < 1))
862 {
863 //
864 // Only cache the first PXE10/WFM11a offer, and discard the others.
865 //
866 Private->OfferIndex[OfferType][0] = Private->OfferNum;
867 Private->OfferCount[OfferType] = 1;
868 } else {
869 return EFI_ABORTED;
870 }
871 } else {
872 //
873 // It's a DHCPv4 offer with yiaddr, and cache them all.
874 //
875 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
876 Private->OfferCount[OfferType]++;
877 }
878 }
879
880 Private->OfferNum++;
881
882 return EFI_SUCCESS;
883}
884
891VOID
893 IN PXEBC_PRIVATE_DATA *Private
894 )
895{
896 UINT32 Index;
897 UINT32 OfferIndex;
898 EFI_DHCP4_PACKET *Offer;
899
900 Private->SelectIndex = 0;
901
902 if (Private->IsOfferSorted) {
903 //
904 // Select offer by default policy.
905 //
906 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
907 //
908 // 1. DhcpPxe10 offer
909 //
910 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
911 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
912 //
913 // 2. DhcpWfm11a offer
914 //
915 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
916 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
917 (Private->OfferCount[PxeOfferTypeProxyPxe10] > 0))
918 {
919 //
920 // 3. DhcpOnly offer and ProxyPxe10 offer.
921 //
922 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
923 Private->SelectProxyType = PxeOfferTypeProxyPxe10;
924 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
925 (Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0))
926 {
927 //
928 // 4. DhcpOnly offer and ProxyWfm11a offer.
929 //
930 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
931 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
932 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
933 //
934 // 5. DhcpBinl offer.
935 //
936 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
937 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
938 (Private->OfferCount[PxeOfferTypeProxyBinl] > 0))
939 {
940 //
941 // 6. DhcpOnly offer and ProxyBinl offer.
942 //
943 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
944 Private->SelectProxyType = PxeOfferTypeProxyBinl;
945 } else {
946 //
947 // 7. DhcpOnly offer with bootfilename.
948 //
949 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
950 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
951 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
952 Private->SelectIndex = OfferIndex + 1;
953 break;
954 }
955 }
956
957 //
958 // 8. Bootp offer with bootfilename.
959 //
960 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
961 if ((Private->SelectIndex == 0) &&
962 (Private->OfferCount[PxeOfferTypeBootp] > 0) &&
963 (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL))
964 {
965 Private->SelectIndex = OfferIndex + 1;
966 }
967 }
968 } else {
969 //
970 // Select offer by received order.
971 //
972 for (Index = 0; Index < Private->OfferNum; Index++) {
973 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
974
975 if (IS_PROXY_DHCP_OFFER (Offer)) {
976 //
977 // Skip proxy offers
978 //
979 continue;
980 }
981
982 if (!Private->IsProxyRecved &&
983 (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly) &&
984 (Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))
985 {
986 //
987 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
988 //
989 continue;
990 }
991
992 //
993 // Record the index of the select offer.
994 //
995 Private->SelectIndex = Index + 1;
996 break;
997 }
998 }
999}
1000
1014 IN PXEBC_PRIVATE_DATA *Private
1015 )
1016{
1018 EFI_DHCP4_PACKET_OPTION **Options;
1019 UINT32 Index;
1020 EFI_DHCP4_PACKET *Offer;
1021 PXEBC_OFFER_TYPE OfferType;
1022 UINT32 ProxyIndex;
1023 UINT32 SelectIndex;
1024 EFI_STATUS Status;
1026 EFI_DHCP4_PACKET *Ack;
1027
1028 ASSERT (Private->SelectIndex > 0);
1029 SelectIndex = (UINT32)(Private->SelectIndex - 1);
1030 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
1031 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4;
1032 Options = Cache4->OptList;
1033 Status = EFI_SUCCESS;
1034
1035 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
1036 //
1037 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1038 //
1039 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
1040 Status = EFI_NO_RESPONSE;
1041 }
1042 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
1043 if (Private->IsProxyRecved) {
1044 //
1045 // DhcpOnly offer is selected, so need try to request bootfile name.
1046 //
1047 ProxyIndex = 0;
1048 if (Private->IsOfferSorted) {
1049 //
1050 // The proxy offer should be determined if select by default policy.
1051 // IsOfferSorted means all offers are labeled by OfferIndex.
1052 //
1053 ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
1054 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
1055
1056 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
1057 //
1058 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1059 //
1060 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
1061 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1062 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
1063 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
1064 break;
1065 }
1066 }
1067
1068 if (Index == Private->OfferCount[Private->SelectProxyType]) {
1069 Status = EFI_NO_RESPONSE;
1070 }
1071 } else {
1072 //
1073 // For other proxy offers, only one is buffered.
1074 //
1075 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
1076 }
1077 } else {
1078 //
1079 // The proxy offer should not be determined if select by received order.
1080 //
1081 Status = EFI_NO_RESPONSE;
1082
1083 for (Index = 0; Index < Private->OfferNum; Index++) {
1084 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1085 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
1086 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
1087 if (!IS_PROXY_DHCP_OFFER (Offer)) {
1088 //
1089 // Skip non proxy DHCPv4 offers.
1090 //
1091 continue;
1092 }
1093
1094 if (OfferType == PxeOfferTypeProxyBinl) {
1095 //
1096 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1097 //
1098 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
1099 continue;
1100 }
1101 }
1102
1103 Private->SelectProxyType = OfferType;
1104 ProxyIndex = Index;
1105 Status = EFI_SUCCESS;
1106 break;
1107 }
1108 }
1109
1110 if (!EFI_ERROR (Status) && (Private->SelectProxyType != PxeOfferTypeProxyBinl)) {
1111 //
1112 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1113 //
1114 Status = PxeBcCopyProxyOffer (Private, ProxyIndex);
1115 }
1116 } else {
1117 //
1118 // Otherwise, the bootfile name must be included in DhcpOnly offer.
1119 //
1120 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
1121 Status = EFI_NOT_FOUND;
1122 }
1123 }
1124 }
1125
1126 if (!EFI_ERROR (Status)) {
1127 //
1128 // All PXE boot information is ready by now.
1129 //
1130 Mode = Private->PxeBc.Mode;
1131 Offer = &Cache4->Packet.Offer;
1132 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack;
1133 if (Cache4->OfferType == PxeOfferTypeBootp) {
1134 //
1135 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1136 // should be taken as ack.
1137 //
1138 Ack = Offer;
1139 }
1140
1141 Status = PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
1142 if (EFI_ERROR (Status)) {
1143 return Status;
1144 }
1145
1146 Mode->DhcpDiscoverValid = TRUE;
1147 }
1148
1149 return Status;
1150}
1151
1173EFIAPI
1175 IN EFI_DHCP4_PROTOCOL *This,
1176 IN VOID *Context,
1177 IN EFI_DHCP4_STATE CurrentState,
1178 IN EFI_DHCP4_EVENT Dhcp4Event,
1179 IN EFI_DHCP4_PACKET *Packet OPTIONAL,
1180 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
1181 )
1182{
1183 PXEBC_PRIVATE_DATA *Private;
1186 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;
1187 UINT16 Value;
1188 EFI_STATUS Status;
1189 BOOLEAN Received;
1190
1191 if ((Dhcp4Event != Dhcp4RcvdOffer) &&
1192 (Dhcp4Event != Dhcp4SelectOffer) &&
1193 (Dhcp4Event != Dhcp4SendDiscover) &&
1194 (Dhcp4Event != Dhcp4RcvdAck))
1195 {
1196 return EFI_SUCCESS;
1197 }
1198
1199 ASSERT (Packet != NULL);
1200
1201 Private = (PXEBC_PRIVATE_DATA *)Context;
1202 Mode = Private->PxeBc.Mode;
1203 Callback = Private->PxeBcCallback;
1204
1205 //
1206 // Override the Maximum DHCP Message Size.
1207 //
1208 MaxMsgSize = PxeBcParseDhcp4Options (
1209 Packet->Dhcp4.Option,
1210 GET_OPTION_BUFFER_LEN (Packet),
1211 DHCP4_TAG_MAXMSG
1212 );
1213 if (MaxMsgSize != NULL) {
1214 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE);
1215 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
1216 }
1217
1218 //
1219 // Callback to user if any packets sent or received.
1220 //
1221 if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {
1222 Received = (BOOLEAN)(Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
1223 Status = Callback->Callback (
1224 Callback,
1225 Private->Function,
1226 Received,
1227 Packet->Length,
1228 (EFI_PXE_BASE_CODE_PACKET *)&Packet->Dhcp4
1229 );
1230 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1231 return EFI_ABORTED;
1232 }
1233 }
1234
1235 Status = EFI_SUCCESS;
1236
1237 switch (Dhcp4Event) {
1238 case Dhcp4SendDiscover:
1239 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1240 //
1241 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1242 //
1243 Status = EFI_ABORTED;
1244 break;
1245 }
1246
1247 //
1248 // Cache the DHCPv4 discover packet to mode data directly.
1249 // It need to check SendGuid as well as Dhcp4SendRequest.
1250 //
1251 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
1252
1253 case Dhcp4SendRequest:
1254 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1255 //
1256 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1257 //
1258 Status = EFI_ABORTED;
1259 break;
1260 }
1261
1262 if (Mode->SendGUID) {
1263 //
1264 // Send the system Guid instead of the MAC address as the hardware address if required.
1265 //
1266 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)Packet->Dhcp4.Header.ClientHwAddr))) {
1267 //
1268 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
1269 //
1270 DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
1271 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1272 }
1273
1274 Packet->Dhcp4.Header.HwAddrLen = (UINT8)sizeof (EFI_GUID);
1275 }
1276
1277 break;
1278
1279 case Dhcp4RcvdOffer:
1280 Status = EFI_NOT_READY;
1281 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1282 //
1283 // Ignore the incoming packets which exceed the maximum length.
1284 //
1285 break;
1286 }
1287
1288 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1289 //
1290 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1291 // the OfferIndex and OfferCount.
1292 // If error happens, just ignore this packet and continue to wait more offer.
1293 //
1294 PxeBcCacheDhcp4Offer (Private, Packet);
1295 }
1296
1297 break;
1298
1299 case Dhcp4SelectOffer:
1300 ASSERT (NewPacket != NULL);
1301
1302 //
1303 // Select offer by the default policy or by order, and record the SelectIndex
1304 // and SelectProxyType.
1305 //
1306 PxeBcSelectDhcp4Offer (Private);
1307
1308 if (Private->SelectIndex == 0) {
1309 Status = EFI_ABORTED;
1310 } else {
1311 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
1312 }
1313
1314 break;
1315
1316 case Dhcp4RcvdAck:
1317 //
1318 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1319 // without verification.
1320 //
1321 ASSERT (Private->SelectIndex != 0);
1322
1323 Status = PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
1324 if (EFI_ERROR (Status)) {
1325 Status = EFI_ABORTED;
1326 }
1327
1328 break;
1329
1330 default:
1331 break;
1332 }
1333
1334 return Status;
1335}
1336
1356 IN PXEBC_PRIVATE_DATA *Private,
1357 IN UINT16 Type,
1358 IN UINT16 *Layer,
1359 IN BOOLEAN UseBis,
1360 IN EFI_IP_ADDRESS *DestIp,
1361 IN UINT16 IpCount,
1363 )
1364{
1365 EFI_PXE_BASE_CODE_UDP_PORT Sport;
1367 EFI_DHCP4_PROTOCOL *Dhcp4;
1369 BOOLEAN IsBCast;
1370 EFI_STATUS Status;
1371 UINT16 RepIndex;
1372 UINT16 SrvIndex;
1373 UINT16 TryIndex;
1374 EFI_DHCP4_LISTEN_POINT ListenPoint;
1375 EFI_DHCP4_PACKET *Response;
1376 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1377 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1378 UINT32 OptCount;
1380 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;
1381 UINT8 VendorOptLen;
1382 UINT32 Xid;
1383
1384 Status = PseudoRandomU32 (&Xid);
1385 if (EFI_ERROR (Status)) {
1386 DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status));
1387 return Status;
1388 }
1389
1390 Mode = Private->PxeBc.Mode;
1391 Dhcp4 = Private->Dhcp4;
1392 Status = EFI_SUCCESS;
1393
1394 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
1395
1396 //
1397 // Use broadcast if destination address not specified.
1398 //
1399 if (DestIp == NULL) {
1400 Sport = PXEBC_DHCP4_S_PORT;
1401 IsBCast = TRUE;
1402 } else {
1403 Sport = PXEBC_BS_DISCOVER_PORT;
1404 IsBCast = FALSE;
1405 }
1406
1407 if (!UseBis && (Layer != NULL)) {
1408 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1409 }
1410
1411 //
1412 // Build all the options for the request packet.
1413 //
1414 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
1415
1416 if (Private->IsDoDiscover) {
1417 //
1418 // Add vendor option of PXE_BOOT_ITEM
1419 //
1420 VendorOptLen = (UINT8)((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
1421 OptList[OptCount] = AllocateZeroPool (VendorOptLen);
1422 if (OptList[OptCount] == NULL) {
1423 return EFI_OUT_OF_RESOURCES;
1424 }
1425
1426 OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;
1427 OptList[OptCount]->Length = (UINT8)(VendorOptLen - 2);
1428 PxeOpt = (EFI_DHCP4_PACKET_OPTION *)OptList[OptCount]->Data;
1429 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;
1430 PxeOpt->Length = (UINT8)sizeof (PXEBC_OPTION_BOOT_ITEM);
1431 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *)PxeOpt->Data;
1432 PxeBootItem->Type = HTONS (Type);
1433 PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;
1434
1435 if (Layer != NULL) {
1436 PxeBootItem->Layer = HTONS (*Layer);
1437 }
1438
1439 OptCount++;
1440 }
1441
1442 //
1443 // Build the request packet with seed packet and option list.
1444 //
1445 Status = Dhcp4->Build (
1446 Dhcp4,
1447 &Private->SeedPacket,
1448 0,
1449 NULL,
1450 OptCount,
1451 OptList,
1452 &Token.Packet
1453 );
1454 //
1455 // Free the vendor option of PXE_BOOT_ITEM.
1456 //
1457 if (Private->IsDoDiscover) {
1458 FreePool (OptList[OptCount - 1]);
1459 }
1460
1461 if (EFI_ERROR (Status)) {
1462 return Status;
1463 }
1464
1465 if (Mode->SendGUID) {
1466 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)Token.Packet->Dhcp4.Header.ClientHwAddr))) {
1467 //
1468 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
1469 //
1470 DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
1471 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1472 }
1473
1474 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)sizeof (EFI_GUID);
1475 }
1476
1477 //
1478 // Set fields of the token for the request packet.
1479 //
1480 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);
1481 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)((IsBCast) ? 0x8000 : 0x0));
1482 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1483
1484 Token.RemotePort = Sport;
1485
1486 if (IsBCast) {
1487 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
1488 } else {
1489 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1490 }
1491
1492 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
1493
1494 if (!IsBCast) {
1495 Token.ListenPointCount = 1;
1496 Token.ListenPoints = &ListenPoint;
1497 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;
1498 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1499 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1500 }
1501
1502 //
1503 // Send out the request packet to discover the bootfile.
1504 //
1505 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
1506 Token.TimeoutValue = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
1507 Token.Packet->Dhcp4.Header.Seconds = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
1508
1509 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
1510 if (Token.Status != EFI_TIMEOUT) {
1511 break;
1512 }
1513 }
1514
1515 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
1516 //
1517 // No server response our PXE request
1518 //
1519 Status = EFI_TIMEOUT;
1520 }
1521
1522 if (!EFI_ERROR (Status)) {
1523 RepIndex = 0;
1524 SrvIndex = 0;
1525 Response = Token.ResponseList;
1526 //
1527 // Find the right PXE Reply according to server address.
1528 //
1529 while (RepIndex < Token.ResponseCount) {
1530 if (Response->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1531 SrvIndex = 0;
1532 RepIndex++;
1533 Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
1534 continue;
1535 }
1536
1537 while (SrvIndex < IpCount) {
1538 if (SrvList[SrvIndex].AcceptAnyResponse) {
1539 break;
1540 }
1541
1542 if ((SrvList[SrvIndex].Type == Type) &&
1543 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr))
1544 {
1545 break;
1546 }
1547
1548 SrvIndex++;
1549 }
1550
1551 if ((IpCount != SrvIndex) || (IpCount == 0)) {
1552 break;
1553 }
1554
1555 SrvIndex = 0;
1556 RepIndex++;
1557 Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
1558 }
1559
1560 if (RepIndex < Token.ResponseCount) {
1561 //
1562 // Cache the right PXE reply packet here, set valid flag later.
1563 // Especially for PXE discover packet, store it into mode data here.
1564 //
1565 if (Private->IsDoDiscover) {
1566 Status = PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
1567 if (EFI_ERROR (Status)) {
1568 goto ON_EXIT;
1569 }
1570
1571 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
1572 } else {
1573 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
1574 if (EFI_ERROR (Status)) {
1575 goto ON_EXIT;
1576 }
1577 }
1578 } else {
1579 //
1580 // Not found the right PXE reply packet.
1581 //
1582 Status = EFI_NOT_FOUND;
1583 }
1584 }
1585
1586ON_EXIT:
1587
1588 if (Token.ResponseList != NULL) {
1589 FreePool (Token.ResponseList);
1590 }
1591
1592 if (Token.Packet != NULL) {
1593 FreePool (Token.Packet);
1594 }
1595
1596 return Status;
1597}
1598
1610 IN PXEBC_PRIVATE_DATA *Private
1611 )
1612{
1613 EFI_STATUS Status;
1614 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
1616 UINTN DataSize;
1617
1618 Ip4Config2 = Private->Ip4Config2;
1619 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
1620 Status = Ip4Config2->GetData (
1621 Ip4Config2,
1623 &DataSize,
1624 &Policy
1625 );
1626 if (EFI_ERROR (Status)) {
1627 return Status;
1628 }
1629
1630 if (Policy != Ip4Config2PolicyStatic) {
1631 Policy = Ip4Config2PolicyStatic;
1632 Status = Ip4Config2->SetData (
1633 Ip4Config2,
1635 sizeof (EFI_IP4_CONFIG2_POLICY),
1636 &Policy
1637 );
1638 if (EFI_ERROR (Status)) {
1639 return Status;
1640 }
1641 }
1642
1643 return EFI_SUCCESS;
1644}
1645
1658 IN PXEBC_PRIVATE_DATA *Private,
1659 IN EFI_DHCP4_PROTOCOL *Dhcp4
1660 )
1661{
1662 EFI_PXE_BASE_CODE_MODE *PxeMode;
1663 EFI_DHCP4_CONFIG_DATA Config;
1665 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1666 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1667 UINT32 OptCount;
1668 EFI_STATUS Status;
1669
1670 ASSERT (Dhcp4 != NULL);
1671
1672 Status = EFI_SUCCESS;
1673 PxeMode = Private->PxeBc.Mode;
1674
1675 //
1676 // Build option list for the request packet.
1677 //
1678 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1679 ASSERT (OptCount > 0);
1680
1681 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1682 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1683
1684 Config.OptionCount = OptCount;
1685 Config.OptionList = OptList;
1687 Config.CallbackContext = Private;
1688 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1689 Config.DiscoverTimeout = mPxeDhcpTimeout;
1690
1691 //
1692 // Configure the DHCPv4 instance for PXE boot.
1693 //
1694 Status = Dhcp4->Configure (Dhcp4, &Config);
1695 if (EFI_ERROR (Status)) {
1696 goto ON_EXIT;
1697 }
1698
1699 //
1700 // Initialize the record fields for DHCPv4 offer in private data.
1701 //
1702 Private->IsProxyRecved = FALSE;
1703 Private->OfferNum = 0;
1704 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1705 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1706
1707 Status = Dhcp4->Start (Dhcp4, NULL);
1708 if (EFI_ERROR (Status)) {
1709 if (Status == EFI_ICMP_ERROR) {
1710 PxeMode->IcmpErrorReceived = TRUE;
1711 }
1712
1713 if ((Status == EFI_TIMEOUT) && (Private->OfferNum > 0)) {
1714 Status = EFI_NO_RESPONSE;
1715 }
1716
1717 goto ON_EXIT;
1718 }
1719
1720 //
1721 // Get the acquired IPv4 address and store them.
1722 //
1723 Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1724 if (EFI_ERROR (Status)) {
1725 goto ON_EXIT;
1726 }
1727
1728 ASSERT (Mode.State == Dhcp4Bound);
1729
1730 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1731 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1732 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1733 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1734 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1735
1736 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
1737 if (EFI_ERROR (Status)) {
1738 goto ON_EXIT;
1739 }
1740
1741 //
1742 // Check the selected offer whether BINL retry is needed.
1743 //
1744 Status = PxeBcHandleDhcp4Offer (Private);
1745
1746 AsciiPrint ("\n Station IP address is ");
1747
1748 PxeBcShowIp4Addr (&Private->StationIp.v4);
1749 AsciiPrint ("\n");
1750
1751ON_EXIT:
1752 if (EFI_ERROR (Status)) {
1753 Dhcp4->Stop (Dhcp4);
1754 Dhcp4->Configure (Dhcp4, NULL);
1755 } else {
1756 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1757 Dhcp4->Configure (Dhcp4, &Config);
1758 Private->IsAddressOk = TRUE;
1759 }
1760
1761 return Status;
1762}
UINT64 UINTN
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_DHCP4_STATE
Definition: Dhcp4.h:98
@ Dhcp4Bound
Definition: Dhcp4.h:118
EFI_DHCP4_EVENT
Definition: Dhcp4.h:141
@ Dhcp4RcvdAck
Definition: Dhcp4.h:161
@ Dhcp4SendRequest
Definition: Dhcp4.h:157
@ Dhcp4SelectOffer
Definition: Dhcp4.h:153
@ Dhcp4RcvdOffer
Definition: Dhcp4.h:149
@ Dhcp4SendDiscover
Definition: Dhcp4.h:145
#define DHCP4_TAG_PAD
Definition: Dhcp.h:19
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_IP4_CONFIG2_POLICY
Definition: Ip4Config2.h:127
@ Ip4Config2PolicyStatic
Definition: Ip4Config2.h:135
@ Ip4Config2DataTypePolicy
Definition: Ip4Config2.h:43
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_STATUS EFIAPI NetLibGetSystemGuid(OUT EFI_GUID *SystemGuid)
Definition: DxeNetLib.c:3325
EFI_STATUS EFIAPI PseudoRandomU32(OUT UINT32 *Output)
Definition: DxeNetLib.c:1011
EFI_STATUS PxeBcDhcp4Discover(IN PXEBC_PRIVATE_DATA *Private, IN UINT16 Type, IN UINT16 *Layer, IN BOOLEAN UseBis, IN EFI_IP_ADDRESS *DestIp, IN UINT16 IpCount, IN EFI_PXE_BASE_CODE_SRVLIST *SrvList)
Definition: PxeBcDhcp4.c:1355
EFI_STATUS PxeBcCopyDhcp4Ack(IN PXEBC_PRIVATE_DATA *Private, IN EFI_DHCP4_PACKET *Ack, IN BOOLEAN Verified)
Definition: PxeBcDhcp4.c:622
EFI_STATUS PxeBcCacheDhcp4Offer(IN PXEBC_PRIVATE_DATA *Private, IN EFI_DHCP4_PACKET *RcvdOffer)
Definition: PxeBcDhcp4.c:801
EFI_STATUS PxeBcHandleDhcp4Offer(IN PXEBC_PRIVATE_DATA *Private)
Definition: PxeBcDhcp4.c:1013
EFI_STATUS PxeBcCacheDhcp4Packet(IN EFI_DHCP4_PACKET *Dst, IN EFI_DHCP4_PACKET *Src)
Definition: PxeBcDhcp4.c:420
EFI_STATUS PxeBcSetIp4Policy(IN PXEBC_PRIVATE_DATA *Private)
Definition: PxeBcDhcp4.c:1609
EFI_DHCP4_PACKET_OPTION * PxeBcParseDhcp4Options(IN UINT8 *Buffer, IN UINT32 Length, IN UINT8 OptTag)
Definition: PxeBcDhcp4.c:42
EFI_STATUS EFIAPI PxeBcDhcp4CallBack(IN EFI_DHCP4_PROTOCOL *This, IN VOID *Context, IN EFI_DHCP4_STATE CurrentState, IN EFI_DHCP4_EVENT Dhcp4Event, IN EFI_DHCP4_PACKET *Packet OPTIONAL, OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL)
Definition: PxeBcDhcp4.c:1174
VOID PxeBcSeedDhcp4Packet(OUT EFI_DHCP4_PACKET *Seed, IN EFI_UDP4_PROTOCOL *Udp4)
Definition: PxeBcDhcp4.c:383
EFI_STATUS PxeBcDhcp4Dora(IN PXEBC_PRIVATE_DATA *Private, IN EFI_DHCP4_PROTOCOL *Dhcp4)
Definition: PxeBcDhcp4.c:1657
EFI_STATUS PxeBcRetryBinlOffer(IN PXEBC_PRIVATE_DATA *Private, IN UINT32 Index)
Definition: PxeBcDhcp4.c:706
EFI_STATUS PxeBcParseDhcp4Packet(IN PXEBC_DHCP4_PACKET_CACHE *Cache4)
Definition: PxeBcDhcp4.c:445
VOID PxeBcSelectDhcp4Offer(IN PXEBC_PRIVATE_DATA *Private)
Definition: PxeBcDhcp4.c:892
VOID PxeBcParseVendorOptions(IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option, IN PXEBC_VENDOR_OPTION *VendorOption)
Definition: PxeBcDhcp4.c:85
UINT32 PxeBcBuildDhcp4Options(IN PXEBC_PRIVATE_DATA *Private, OUT EFI_DHCP4_PACKET_OPTION **OptList, IN UINT8 *Buffer, IN BOOLEAN NeedMsgType)
Definition: PxeBcDhcp4.c:217
EFI_STATUS PxeBcCopyProxyOffer(IN PXEBC_PRIVATE_DATA *Private, IN UINT32 OfferIndex)
Definition: PxeBcDhcp4.c:661
EFI_STATUS PxeBcFlushStationIp(PXEBC_PRIVATE_DATA *Private, EFI_IP_ADDRESS *StationIp OPTIONAL, EFI_IP_ADDRESS *SubnetMask OPTIONAL)
Definition: PxeBcSupport.c:24
VOID PxeBcShowIp4Addr(IN EFI_IPv4_ADDRESS *Ip)
VOID PxeBcUintnToAscDecWithFormat(IN UINTN Number, IN UINT8 *Buffer, IN INTN Length)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINTN EFIAPI AsciiPrint(IN CONST CHAR8 *Format,...)
Definition: UefiLibPrint.c:250
EFI_PXE_BASE_CODE_MODE * Mode
Definition: PxeBaseCode.h:928
VOID * CallbackContext
Definition: Dhcp4.h:282
EFI_DHCP4_PACKET_OPTION ** OptionList
Definition: Dhcp4.h:294
UINT32 * DiscoverTimeout
Definition: Dhcp4.h:253
UINT32 OptionCount
Definition: Dhcp4.h:286
EFI_DHCP4_CALLBACK Dhcp4Callback
Definition: Dhcp4.h:278
UINT32 DiscoverTryCount
Definition: Dhcp4.h:247
EFI_IPv4_ADDRESS ClientAddr
Client IP address from client.
Definition: Dhcp4.h:59
EFI_IPv4_ADDRESS ServerAddr
IP address of next server in bootstrap.
Definition: Dhcp4.h:61
UINT8 ClientHwAddr[16]
Client hardware address.
Definition: Dhcp4.h:63
EFI_IPv4_ADDRESS YourAddr
Client IP address from server.
Definition: Dhcp4.h:60
EFI_IPv4_ADDRESS ListenAddress
Definition: Dhcp4.h:344
EFI_IPv4_ADDRESS SubnetMask
Definition: Dhcp4.h:349
EFI_IPv4_ADDRESS SubnetMask
Definition: Dhcp4.h:327
EFI_DHCP4_STATE State
Definition: Dhcp4.h:301
EFI_IPv4_ADDRESS RouterAddress
Definition: Dhcp4.h:323
EFI_IPv4_ADDRESS ClientAddress
Definition: Dhcp4.h:310
UINT8 Option[1]
Definition: Dhcp4.h:93
UINT32 Length
Definition: Dhcp4.h:79
EFI_DHCP4_HEADER Header
Definition: Dhcp4.h:85
UINT32 Size
Definition: Dhcp4.h:74
EFI_IPv4_ADDRESS RemoteAddress
Definition: Dhcp4.h:370
EFI_DHCP4_LISTEN_POINT * ListenPoints
Definition: Dhcp4.h:387
EFI_DHCP4_PACKET * Packet
Definition: Dhcp4.h:395
EFI_IPv4_ADDRESS GatewayAddress
Definition: Dhcp4.h:378
EFI_DHCP4_PACKET * ResponseList
Definition: Dhcp4.h:403
EFI_MAC_ADDRESS CurrentAddress
Definition: Base.h:213