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