VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c@ 80721

Last change on this file since 80721 was 80721, checked in by vboxsync, 5 years ago

Devices/EFI/FirmwareNew: Start upgrade process to edk2-stable201908 (compiles on Windows and works to some extent), bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette