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