]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp4.c
1 /** @file
2 Functions implementation related with DHCPv4 for UefiPxeBc Driver.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "PxeBcImpl.h"
11
12 //
13 // This is a map from the interested DHCP4 option tags' index to the tag value.
14 //
15 UINT8 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 //
28 UINT32 mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
29
30 /**
31 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
32
33 @param[in] Buffer Pointer to the option buffer.
34 @param[in] Length Length of the option buffer.
35 @param[in] OptTag Tag of the required option.
36
37 @retval NULL Failed to find the required option.
38 @retval Others The position of the required option.
39
40 **/
41 EFI_DHCP4_PACKET_OPTION *
42 PxeBcParseDhcp4Options (
43 IN UINT8 *Buffer,
44 IN UINT32 Length,
45 IN UINT8 OptTag
46 )
47 {
48 EFI_DHCP4_PACKET_OPTION *Option;
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
77 /**
78 Parse the PXE vendor options and extract the information from them.
79
80 @param[in] Dhcp4Option Pointer to vendor options in buffer.
81 @param[in] VendorOption Pointer to structure to store information in vendor options.
82
83 **/
84 VOID
85 PxeBcParseVendorOptions (
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
204 /**
205 Build the options buffer for the DHCPv4 request packet.
206
207 @param[in] Private Pointer to PxeBc private data.
208 @param[out] OptList Pointer to the option pointer array.
209 @param[in] Buffer Pointer to the buffer to contain the option list.
210 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
211 Otherwise, it is not necessary.
212
213 @return Index The count of the built-in options.
214
215 **/
216 UINT32
217 PxeBcBuildDhcp4Options (
218 IN PXEBC_PRIVATE_DATA *Private,
219 OUT EFI_DHCP4_PACKET_OPTION **OptList,
220 IN UINT8 *Buffer,
221 IN BOOLEAN NeedMsgType
222 )
223 {
224 UINT32 Index;
225 PXEBC_DHCP4_OPTION_ENTRY OptEnt;
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,
356 sizeof (PXEBC_DHCP4_OPTION_CLID)
357 );
358 PxeBcUintnToAscDecWithFormat (
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
375 /**
376 Create a template DHCPv4 packet as a seed.
377
378 @param[out] Seed Pointer to the seed packet.
379 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
380
381 **/
382 VOID
383 PxeBcSeedDhcp4Packet (
384 OUT EFI_DHCP4_PACKET *Seed,
385 IN EFI_UDP4_PROTOCOL *Udp4
386 )
387 {
388 EFI_SIMPLE_NETWORK_MODE Mode;
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
409 /**
410 Cache the DHCPv4 packet.
411
412 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
413 @param[in] Src Pointer to the DHCPv4 packet to be cached.
414
415 @retval EFI_SUCCESS Packet is copied.
416 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
417
418 **/
419 EFI_STATUS
420 PxeBcCacheDhcp4Packet (
421 IN EFI_DHCP4_PACKET *Dst,
422 IN EFI_DHCP4_PACKET *Src
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
435 /**
436 Parse the cached DHCPv4 packet, including all the options.
437
438 @param[in] Cache4 Pointer to cached DHCPv4 packet.
439
440 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
441 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
442
443 **/
444 EFI_STATUS
445 PxeBcParseDhcp4Packet (
446 IN PXEBC_DHCP4_PACKET_CACHE *Cache4
447 )
448 {
449 EFI_DHCP4_PACKET *Offer;
450 EFI_DHCP4_PACKET_OPTION **Options;
451 EFI_DHCP4_PACKET_OPTION *Option;
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] -
560 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[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
610 /**
611 Cache the DHCPv4 ack packet, and parse it on demand.
612
613 @param[in] Private Pointer to PxeBc private data.
614 @param[in] Ack Pointer to the DHCPv4 ack packet.
615 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
616
617 @retval EFI_SUCCESS Cache and parse the packet successfully.
618 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
619
620 **/
621 EFI_STATUS
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 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
650 /**
651 Cache the DHCPv4 proxy offer packet according to the received order.
652
653 @param[in] Private Pointer to PxeBc private data.
654 @param[in] OfferIndex The received order of offer packets.
655
656 @retval EFI_SUCCESS Cache and parse the packet successfully.
657 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
658
659 **/
660 EFI_STATUS
661 PxeBcCopyProxyOffer (
662 IN PXEBC_PRIVATE_DATA *Private,
663 IN UINT32 OfferIndex
664 )
665 {
666 EFI_PXE_BASE_CODE_MODE *Mode;
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
695 /**
696 Retry to request bootfile name by the BINL offer.
697
698 @param[in] Private Pointer to PxeBc private data.
699 @param[in] Index The received order of offer packets.
700
701 @retval EFI_SUCCESS Successfully retried to request bootfile name.
702 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.
703
704 **/
705 EFI_STATUS
706 PxeBcRetryBinlOffer (
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;
714 PXEBC_DHCP4_PACKET_CACHE *Cache4;
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
790 /**
791 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
792
793 @param[in] Private Pointer to PxeBc private data.
794 @param[in] RcvdOffer Pointer to the received offer packet.
795
796 @retval EFI_SUCCESS Cache and parse the packet successfully.
797 @retval Others Operation failed.
798
799 **/
800 EFI_STATUS
801 PxeBcCacheDhcp4Offer (
802 IN PXEBC_PRIVATE_DATA *Private,
803 IN EFI_DHCP4_PACKET *RcvdOffer
804 )
805 {
806 PXEBC_DHCP4_PACKET_CACHE *Cache4;
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
885 /**
886 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
887
888 @param[in] Private Pointer to PxeBc private data.
889
890 **/
891 VOID
892 PxeBcSelectDhcp4Offer (
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
1001 /**
1002 Handle the DHCPv4 offer packet.
1003
1004 @param[in] Private Pointer to PxeBc private data.
1005
1006 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
1007 @retval EFI_NO_RESPONSE No response to the following request packet.
1008 @retval EFI_NOT_FOUND No boot filename received.
1009 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1010
1011 **/
1012 EFI_STATUS
1013 PxeBcHandleDhcp4Offer (
1014 IN PXEBC_PRIVATE_DATA *Private
1015 )
1016 {
1017 PXEBC_DHCP4_PACKET_CACHE *Cache4;
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;
1025 EFI_PXE_BASE_CODE_MODE *Mode;
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
1152 /**
1153 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1154 to intercept events that occurred in the configuration process.
1155
1156 @param[in] This Pointer to the EFI DHCPv4 Protocol.
1157 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1158 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
1159 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
1160 state transition.
1161 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
1162 @param[out] NewPacket The packet that is used to replace the above Packet.
1163
1164 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1165 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1166 driver will continue to wait for more DHCPOFFER packets until the
1167 retry timeout expires.
1168 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
1169 and return to the Dhcp4Init or Dhcp4InitReboot state.
1170
1171 **/
1172 EFI_STATUS
1173 EFIAPI
1174 PxeBcDhcp4CallBack (
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;
1184 EFI_PXE_BASE_CODE_MODE *Mode;
1185 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
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
1337 /**
1338 Build and send out the request packet for the bootfile, and parse the reply.
1339
1340 @param[in] Private Pointer to PxeBc private data.
1341 @param[in] Type PxeBc option boot item type.
1342 @param[in] Layer Pointer to option boot item layer.
1343 @param[in] UseBis Use BIS or not.
1344 @param[in] DestIp Pointer to the server address.
1345 @param[in] IpCount The total count of the server address.
1346 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1347
1348 @retval EFI_SUCCESS Successfully discovered boot file.
1349 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
1350 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1351 @retval Others Failed to discover boot file.
1352
1353 **/
1354 EFI_STATUS
1355 PxeBcDhcp4Discover (
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,
1362 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList
1363 )
1364 {
1365 EFI_PXE_BASE_CODE_UDP_PORT Sport;
1366 EFI_PXE_BASE_CODE_MODE *Mode;
1367 EFI_DHCP4_PROTOCOL *Dhcp4;
1368 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
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;
1379 EFI_DHCP4_PACKET_OPTION *PxeOpt;
1380 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;
1381 UINT8 VendorOptLen;
1382 UINT32 Xid;
1383
1384 Mode = Private->PxeBc.Mode;
1385 Dhcp4 = Private->Dhcp4;
1386 Status = EFI_SUCCESS;
1387
1388 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
1389
1390 //
1391 // Use broadcast if destination address not specified.
1392 //
1393 if (DestIp == NULL) {
1394 Sport = PXEBC_DHCP4_S_PORT;
1395 IsBCast = TRUE;
1396 } else {
1397 Sport = PXEBC_BS_DISCOVER_PORT;
1398 IsBCast = FALSE;
1399 }
1400
1401 if (!UseBis && (Layer != NULL)) {
1402 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1403 }
1404
1405 //
1406 // Build all the options for the request packet.
1407 //
1408 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
1409
1410 if (Private->IsDoDiscover) {
1411 //
1412 // Add vendor option of PXE_BOOT_ITEM
1413 //
1414 VendorOptLen = (UINT8)((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
1415 OptList[OptCount] = AllocateZeroPool (VendorOptLen);
1416 if (OptList[OptCount] == NULL) {
1417 return EFI_OUT_OF_RESOURCES;
1418 }
1419
1420 OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;
1421 OptList[OptCount]->Length = (UINT8)(VendorOptLen - 2);
1422 PxeOpt = (EFI_DHCP4_PACKET_OPTION *)OptList[OptCount]->Data;
1423 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;
1424 PxeOpt->Length = (UINT8)sizeof (PXEBC_OPTION_BOOT_ITEM);
1425 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *)PxeOpt->Data;
1426 PxeBootItem->Type = HTONS (Type);
1427 PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;
1428
1429 if (Layer != NULL) {
1430 PxeBootItem->Layer = HTONS (*Layer);
1431 }
1432
1433 OptCount++;
1434 }
1435
1436 //
1437 // Build the request packet with seed packet and option list.
1438 //
1439 Status = Dhcp4->Build (
1440 Dhcp4,
1441 &Private->SeedPacket,
1442 0,
1443 NULL,
1444 OptCount,
1445 OptList,
1446 &Token.Packet
1447 );
1448 //
1449 // Free the vendor option of PXE_BOOT_ITEM.
1450 //
1451 if (Private->IsDoDiscover) {
1452 FreePool (OptList[OptCount - 1]);
1453 }
1454
1455 if (EFI_ERROR (Status)) {
1456 return Status;
1457 }
1458
1459 if (Mode->SendGUID) {
1460 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)Token.Packet->Dhcp4.Header.ClientHwAddr))) {
1461 //
1462 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
1463 //
1464 DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
1465 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1466 }
1467
1468 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)sizeof (EFI_GUID);
1469 }
1470
1471 //
1472 // Set fields of the token for the request packet.
1473 //
1474 Xid = NET_RANDOM (NetRandomInitSeed ());
1475 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);
1476 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)((IsBCast) ? 0x8000 : 0x0));
1477 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1478
1479 Token.RemotePort = Sport;
1480
1481 if (IsBCast) {
1482 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
1483 } else {
1484 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1485 }
1486
1487 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
1488
1489 if (!IsBCast) {
1490 Token.ListenPointCount = 1;
1491 Token.ListenPoints = &ListenPoint;
1492 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;
1493 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1494 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1495 }
1496
1497 //
1498 // Send out the request packet to discover the bootfile.
1499 //
1500 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
1501 Token.TimeoutValue = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
1502 Token.Packet->Dhcp4.Header.Seconds = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
1503
1504 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
1505 if (Token.Status != EFI_TIMEOUT) {
1506 break;
1507 }
1508 }
1509
1510 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
1511 //
1512 // No server response our PXE request
1513 //
1514 Status = EFI_TIMEOUT;
1515 }
1516
1517 if (!EFI_ERROR (Status)) {
1518 RepIndex = 0;
1519 SrvIndex = 0;
1520 Response = Token.ResponseList;
1521 //
1522 // Find the right PXE Reply according to server address.
1523 //
1524 while (RepIndex < Token.ResponseCount) {
1525 if (Response->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1526 SrvIndex = 0;
1527 RepIndex++;
1528 Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
1529 continue;
1530 }
1531
1532 while (SrvIndex < IpCount) {
1533 if (SrvList[SrvIndex].AcceptAnyResponse) {
1534 break;
1535 }
1536
1537 if ((SrvList[SrvIndex].Type == Type) &&
1538 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr))
1539 {
1540 break;
1541 }
1542
1543 SrvIndex++;
1544 }
1545
1546 if ((IpCount != SrvIndex) || (IpCount == 0)) {
1547 break;
1548 }
1549
1550 SrvIndex = 0;
1551 RepIndex++;
1552 Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
1553 }
1554
1555 if (RepIndex < Token.ResponseCount) {
1556 //
1557 // Cache the right PXE reply packet here, set valid flag later.
1558 // Especially for PXE discover packet, store it into mode data here.
1559 //
1560 if (Private->IsDoDiscover) {
1561 Status = PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
1562 if (EFI_ERROR (Status)) {
1563 goto ON_EXIT;
1564 }
1565
1566 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
1567 } else {
1568 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
1569 if (EFI_ERROR (Status)) {
1570 goto ON_EXIT;
1571 }
1572 }
1573 } else {
1574 //
1575 // Not found the right PXE reply packet.
1576 //
1577 Status = EFI_NOT_FOUND;
1578 }
1579 }
1580
1581 ON_EXIT:
1582
1583 if (Token.ResponseList != NULL) {
1584 FreePool (Token.ResponseList);
1585 }
1586
1587 if (Token.Packet != NULL) {
1588 FreePool (Token.Packet);
1589 }
1590
1591 return Status;
1592 }
1593
1594 /**
1595 Switch the Ip4 policy to static.
1596
1597 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1598
1599 @retval EFI_SUCCESS The policy is already configured to static.
1600 @retval Others Other error as indicated..
1601
1602 **/
1603 EFI_STATUS
1604 PxeBcSetIp4Policy (
1605 IN PXEBC_PRIVATE_DATA *Private
1606 )
1607 {
1608 EFI_STATUS Status;
1609 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
1610 EFI_IP4_CONFIG2_POLICY Policy;
1611 UINTN DataSize;
1612
1613 Ip4Config2 = Private->Ip4Config2;
1614 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
1615 Status = Ip4Config2->GetData (
1616 Ip4Config2,
1617 Ip4Config2DataTypePolicy,
1618 &DataSize,
1619 &Policy
1620 );
1621 if (EFI_ERROR (Status)) {
1622 return Status;
1623 }
1624
1625 if (Policy != Ip4Config2PolicyStatic) {
1626 Policy = Ip4Config2PolicyStatic;
1627 Status = Ip4Config2->SetData (
1628 Ip4Config2,
1629 Ip4Config2DataTypePolicy,
1630 sizeof (EFI_IP4_CONFIG2_POLICY),
1631 &Policy
1632 );
1633 if (EFI_ERROR (Status)) {
1634 return Status;
1635 }
1636 }
1637
1638 return EFI_SUCCESS;
1639 }
1640
1641 /**
1642 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1643
1644 @param[in] Private Pointer to PxeBc private data.
1645 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
1646
1647 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
1648 @retval Others Failed to finish the D.O.R.A process.
1649
1650 **/
1651 EFI_STATUS
1652 PxeBcDhcp4Dora (
1653 IN PXEBC_PRIVATE_DATA *Private,
1654 IN EFI_DHCP4_PROTOCOL *Dhcp4
1655 )
1656 {
1657 EFI_PXE_BASE_CODE_MODE *PxeMode;
1658 EFI_DHCP4_CONFIG_DATA Config;
1659 EFI_DHCP4_MODE_DATA Mode;
1660 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1661 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1662 UINT32 OptCount;
1663 EFI_STATUS Status;
1664
1665 ASSERT (Dhcp4 != NULL);
1666
1667 Status = EFI_SUCCESS;
1668 PxeMode = Private->PxeBc.Mode;
1669
1670 //
1671 // Build option list for the request packet.
1672 //
1673 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1674 ASSERT (OptCount > 0);
1675
1676 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1677 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1678
1679 Config.OptionCount = OptCount;
1680 Config.OptionList = OptList;
1681 Config.Dhcp4Callback = PxeBcDhcp4CallBack;
1682 Config.CallbackContext = Private;
1683 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1684 Config.DiscoverTimeout = mPxeDhcpTimeout;
1685
1686 //
1687 // Configure the DHCPv4 instance for PXE boot.
1688 //
1689 Status = Dhcp4->Configure (Dhcp4, &Config);
1690 if (EFI_ERROR (Status)) {
1691 goto ON_EXIT;
1692 }
1693
1694 //
1695 // Initialize the record fields for DHCPv4 offer in private data.
1696 //
1697 Private->IsProxyRecved = FALSE;
1698 Private->OfferNum = 0;
1699 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1700 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1701
1702 Status = Dhcp4->Start (Dhcp4, NULL);
1703 if (EFI_ERROR (Status)) {
1704 if (Status == EFI_ICMP_ERROR) {
1705 PxeMode->IcmpErrorReceived = TRUE;
1706 }
1707
1708 if ((Status == EFI_TIMEOUT) && (Private->OfferNum > 0)) {
1709 Status = EFI_NO_RESPONSE;
1710 }
1711
1712 goto ON_EXIT;
1713 }
1714
1715 //
1716 // Get the acquired IPv4 address and store them.
1717 //
1718 Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1719 if (EFI_ERROR (Status)) {
1720 goto ON_EXIT;
1721 }
1722
1723 ASSERT (Mode.State == Dhcp4Bound);
1724
1725 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1726 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1727 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1728 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1729 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1730
1731 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
1732 if (EFI_ERROR (Status)) {
1733 goto ON_EXIT;
1734 }
1735
1736 //
1737 // Check the selected offer whether BINL retry is needed.
1738 //
1739 Status = PxeBcHandleDhcp4Offer (Private);
1740
1741 AsciiPrint ("\n Station IP address is ");
1742
1743 PxeBcShowIp4Addr (&Private->StationIp.v4);
1744 AsciiPrint ("\n");
1745
1746 ON_EXIT:
1747 if (EFI_ERROR (Status)) {
1748 Dhcp4->Stop (Dhcp4);
1749 Dhcp4->Configure (Dhcp4, NULL);
1750 } else {
1751 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1752 Dhcp4->Configure (Dhcp4, &Config);
1753 Private->IsAddressOk = TRUE;
1754 }
1755
1756 return Status;
1757 }