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