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