]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
EmulatorPkg/PeiEmuSerialPortLib: Update the INF file Guid
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDhcp4.c
CommitLineData
d933e70a
JW
1/** @file\r
2 Functions implementation related with DHCPv4 for HTTP boot driver.\r
3\r
f75a7f56 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
ecf98fbc 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
d933e70a
JW
6\r
7**/\r
8\r
9#include "HttpBootDxe.h"\r
10\r
11//\r
12// This is a map from the interested DHCP4 option tags' index to the tag value.\r
13//\r
14UINT8 mInterestedDhcp4Tags[HTTP_BOOT_DHCP4_TAG_INDEX_MAX] = {\r
142c00c3
ZL
15 DHCP4_TAG_BOOTFILE_LEN,\r
16 DHCP4_TAG_OVERLOAD,\r
17 DHCP4_TAG_MSG_TYPE,\r
18 DHCP4_TAG_SERVER_ID,\r
19 DHCP4_TAG_VENDOR_CLASS_ID,\r
20 DHCP4_TAG_BOOTFILE,\r
21 DHCP4_TAG_DNS_SERVER\r
d933e70a
JW
22};\r
23\r
24//\r
25// There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec.\r
26//\r
27UINT32 mHttpDhcpTimeout[4] = {4, 8, 16, 32};\r
28\r
29/**\r
30 Build the options buffer for the DHCPv4 request packet.\r
31\r
32 @param[in] Private Pointer to HTTP boot driver private data.\r
33 @param[out] OptList Pointer to the option pointer array.\r
34 @param[in] Buffer Pointer to the buffer to contain the option list.\r
35\r
36 @return Index The count of the built-in options.\r
37\r
38**/\r
39UINT32\r
40HttpBootBuildDhcp4Options (\r
41 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
42 OUT EFI_DHCP4_PACKET_OPTION **OptList,\r
43 IN UINT8 *Buffer\r
44 )\r
45{\r
46 HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt;\r
47 UINT16 Value;\r
48 UINT32 Index;\r
49\r
50 Index = 0;\r
51 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
52\r
53 //\r
54 // Append parameter request list option.\r
55 //\r
142c00c3 56 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;\r
d933e70a
JW
57 OptList[Index]->Length = 27;\r
58 OptEnt.Para = (HTTP_BOOT_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
142c00c3
ZL
59 OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;\r
60 OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;\r
61 OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;\r
62 OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;\r
63 OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;\r
64 OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;\r
65 OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;\r
66 OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;\r
67 OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;\r
68 OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;\r
69 OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;\r
70 OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;\r
71 OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;\r
72 OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;\r
73 OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;\r
74 OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;\r
75 OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;\r
76 OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;\r
77 OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;\r
78 OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;\r
79 OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;\r
80 OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;\r
81 OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;\r
82 OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;\r
83 OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;\r
84 OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;\r
d933e70a
JW
85 Index++;\r
86 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
87\r
88 //\r
89 // Append UUID/Guid-based client identifier option\r
90 //\r
142c00c3 91 OptList[Index]->OpCode = DHCP4_TAG_UUID;\r
d933e70a
JW
92 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UUID);\r
93 OptEnt.Uuid = (HTTP_BOOT_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
94 OptEnt.Uuid->Type = 0;\r
95 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {\r
96 //\r
97 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
98 //\r
99 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
100 }\r
101 Index++;\r
102 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
103\r
104 //\r
105 // Append client network device interface option\r
106 //\r
142c00c3 107 OptList[Index]->OpCode = DHCP4_TAG_UNDI;\r
d933e70a
JW
108 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI);\r
109 OptEnt.Undi = (HTTP_BOOT_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
110\r
111 if (Private->Nii != NULL) {\r
112 OptEnt.Undi->Type = Private->Nii->Type;\r
113 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
114 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
115 } else {\r
116 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
117 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
118 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
119 }\r
120\r
121 Index++;\r
122 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
123\r
124 //\r
125 // Append client system architecture option\r
126 //\r
142c00c3 127 OptList[Index]->OpCode = DHCP4_TAG_ARCH;\r
d933e70a
JW
128 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH);\r
129 OptEnt.Arch = (HTTP_BOOT_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
130 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);\r
131 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
132 Index++;\r
133 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
134\r
135 //\r
136 // Append vendor class identify option\r
137 //\r
142c00c3 138 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;\r
d933e70a
JW
139 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_CLID);\r
140 OptEnt.Clid = (HTTP_BOOT_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
141 CopyMem (\r
142 OptEnt.Clid,\r
143 DEFAULT_CLASS_ID_DATA,\r
144 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID)\r
145 );\r
146 HttpBootUintnToAscDecWithFormat (\r
147 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,\r
148 OptEnt.Clid->ArchitectureType,\r
149 sizeof (OptEnt.Clid->ArchitectureType)\r
150 );\r
151\r
152 if (Private->Nii != NULL) {\r
153 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
154 HttpBootUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
155 HttpBootUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
156 }\r
157\r
158 Index++;\r
159\r
160 return Index;\r
161}\r
162\r
163/**\r
164 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.\r
165\r
166 @param[in] Buffer Pointer to the option buffer.\r
167 @param[in] Length Length of the option buffer.\r
168 @param[in] OptTag Tag of the required option.\r
169\r
170 @retval NULL Failed to find the required option.\r
171 @retval Others The position of the required option.\r
172\r
173**/\r
174EFI_DHCP4_PACKET_OPTION *\r
175HttpBootParseDhcp4Options (\r
176 IN UINT8 *Buffer,\r
177 IN UINT32 Length,\r
178 IN UINT8 OptTag\r
179 )\r
180{\r
181 EFI_DHCP4_PACKET_OPTION *Option;\r
182 UINT32 Offset;\r
183\r
184 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
185 Offset = 0;\r
186\r
142c00c3 187 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {\r
d933e70a
JW
188\r
189 if (Option->OpCode == OptTag) {\r
190 //\r
191 // Found the required option.\r
192 //\r
193 return Option;\r
194 }\r
195\r
196 //\r
197 // Skip the current option to the next.\r
198 //\r
142c00c3 199 if (Option->OpCode == DHCP4_TAG_PAD) {\r
d933e70a
JW
200 Offset++;\r
201 } else {\r
202 Offset += Option->Length + 2;\r
203 }\r
204\r
205 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
206 }\r
207\r
208 return NULL;\r
209}\r
210\r
211/**\r
212 Cache the DHCPv4 packet.\r
213\r
214 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.\r
215 @param[in] Src Pointer to the DHCPv4 packet to be cached.\r
216\r
a35dc649
FS
217 @retval EFI_SUCCESS Packet is copied.\r
218 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
219\r
d933e70a 220**/\r
a35dc649 221EFI_STATUS\r
d933e70a
JW
222HttpBootCacheDhcp4Packet (\r
223 IN EFI_DHCP4_PACKET *Dst,\r
224 IN EFI_DHCP4_PACKET *Src\r
225 )\r
226{\r
a35dc649
FS
227 if (Dst->Size < Src->Length) {\r
228 return EFI_BUFFER_TOO_SMALL;\r
229 }\r
d933e70a
JW
230\r
231 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
232 Dst->Length = Src->Length;\r
a35dc649
FS
233\r
234 return EFI_SUCCESS;\r
d933e70a
JW
235}\r
236\r
237/**\r
238 Parse the cached DHCPv4 packet, including all the options.\r
239\r
240 @param[in] Cache4 Pointer to cached DHCPv4 packet.\r
241\r
242 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.\r
243 @retval EFI_DEVICE_ERROR Failed to parse an invalid packet.\r
244\r
245**/\r
246EFI_STATUS\r
247HttpBootParseDhcp4Packet (\r
248 IN HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4\r
249 )\r
250{\r
251 EFI_DHCP4_PACKET *Offer;\r
252 EFI_DHCP4_PACKET_OPTION **Options;\r
253 UINTN Index;\r
254 EFI_DHCP4_PACKET_OPTION *Option;\r
255 BOOLEAN IsProxyOffer;\r
256 BOOLEAN IsHttpOffer;\r
257 BOOLEAN IsDnsOffer;\r
258 BOOLEAN IpExpressedUri;\r
259 UINT8 *Ptr8;\r
260 EFI_STATUS Status;\r
261 HTTP_BOOT_OFFER_TYPE OfferType;\r
262 EFI_IPv4_ADDRESS IpAddr;\r
b7f28e1a 263 BOOLEAN FileFieldOverloaded;\r
f75a7f56 264\r
d933e70a
JW
265 IsDnsOffer = FALSE;\r
266 IpExpressedUri = FALSE;\r
267 IsProxyOffer = FALSE;\r
268 IsHttpOffer = FALSE;\r
b7f28e1a 269 FileFieldOverloaded = FALSE;\r
d933e70a
JW
270\r
271 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));\r
272\r
273 Offer = &Cache4->Packet.Offer;\r
274 Options = Cache4->OptList;\r
275\r
276 //\r
277 // Parse DHCPv4 options in this offer, and store the pointers.\r
278 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
279 //\r
280 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
281 Options[Index] = HttpBootParseDhcp4Options (\r
282 Offer->Dhcp4.Option,\r
283 GET_OPTION_BUFFER_LEN (Offer),\r
284 mInterestedDhcp4Tags[Index]\r
285 );\r
286 }\r
287 //\r
f75a7f56 288 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.\r
d933e70a
JW
289 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
290 //\r
291 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD];\r
292 if (Option != NULL) {\r
293 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) {\r
b7f28e1a 294 FileFieldOverloaded = TRUE;\r
d933e70a
JW
295 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
296 if (Options[Index] == NULL) {\r
297 Options[Index] = HttpBootParseDhcp4Options (\r
298 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
299 sizeof (Offer->Dhcp4.Header.BootFileName),\r
300 mInterestedDhcp4Tags[Index]\r
301 );\r
302 }\r
303 }\r
304 }\r
305 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
306 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
307 if (Options[Index] == NULL) {\r
308 Options[Index] = HttpBootParseDhcp4Options (\r
309 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
310 sizeof (Offer->Dhcp4.Header.ServerName),\r
311 mInterestedDhcp4Tags[Index]\r
312 );\r
313 }\r
314 }\r
315 }\r
316 }\r
317\r
318 //\r
319 // The offer with "yiaddr" is a proxy offer.\r
320 //\r
321 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
322 IsProxyOffer = TRUE;\r
323 }\r
324\r
325 //\r
b659408b 326 // The offer with "HTTPClient" is a Http offer.\r
d933e70a
JW
327 //\r
328 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];\r
1ba4a4df
LE
329 if ((Option != NULL) && (Option->Length >= 10) &&\r
330 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 0)) {\r
d933e70a
JW
331 IsHttpOffer = TRUE;\r
332 }\r
333\r
334 //\r
335 // The offer with Domain Server is a DNS offer.\r
336 //\r
337 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];\r
338 if (Option != NULL) {\r
339 IsDnsOffer = TRUE;\r
340 }\r
341\r
342 //\r
343 // Parse boot file name:\r
344 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.\r
345 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
346 // Otherwise, read from boot file field in DHCP header.\r
347 //\r
348 if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
349 //\r
350 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
351 // terminated string. So force to append null terminated character at the end of string.\r
352 //\r
353 Ptr8 = (UINT8*)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
354 Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
355 if (*(Ptr8 - 1) != '\0') {\r
356 *Ptr8 = '\0';\r
357 }\r
b7f28e1a 358 } else if (!FileFieldOverloaded && Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
d933e70a
JW
359 //\r
360 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
361 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
362 //\r
363 Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
364 (&Offer->Dhcp4.Header.BootFileName[0] -\r
365 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
366 }\r
367\r
368 //\r
369 // Http offer must have a boot URI.\r
370 //\r
371 if (IsHttpOffer && Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
372 return EFI_DEVICE_ERROR;\r
373 }\r
374\r
375 //\r
f75a7f56 376 // Try to retrieve the IP of HTTP server from URI.\r
d933e70a
JW
377 //\r
378 if (IsHttpOffer) {\r
379 Status = HttpParseUrl (\r
380 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
381 (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data),\r
382 FALSE,\r
383 &Cache4->UriParser\r
384 );\r
385 if (EFI_ERROR (Status)) {\r
386 return EFI_DEVICE_ERROR;\r
387 }\r
388\r
389 Status = HttpUrlGetIp4 (\r
390 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
391 Cache4->UriParser,\r
392 &IpAddr\r
393 );\r
394 IpExpressedUri = !EFI_ERROR (Status);\r
395 }\r
396\r
397 //\r
398 // Determine offer type of the DHCPv4 packet.\r
399 //\r
400 if (IsHttpOffer) {\r
401 if (IpExpressedUri) {\r
fa848a40
FS
402 if (IsProxyOffer) {\r
403 OfferType = HttpOfferTypeProxyIpUri;\r
404 } else {\r
405 OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;\r
406 }\r
d933e70a
JW
407 } else {\r
408 if (!IsProxyOffer) {\r
409 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
410 } else {\r
411 OfferType = HttpOfferTypeProxyNameUri;\r
412 }\r
413 }\r
414\r
415 } else {\r
416 if (!IsProxyOffer) {\r
417 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
418 } else {\r
0dc59296
JW
419 if (Cache4->UriParser != NULL) {\r
420 FreePool (Cache4->UriParser);\r
421 }\r
d933e70a
JW
422 return EFI_DEVICE_ERROR;\r
423 }\r
424 }\r
f75a7f56 425\r
d933e70a
JW
426 Cache4->OfferType = OfferType;\r
427 return EFI_SUCCESS;\r
428}\r
429\r
430/**\r
431 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
432\r
433 @param[in] Private Pointer to HTTP boot driver private data.\r
434 @param[in] RcvdOffer Pointer to the received offer packet.\r
435\r
a35dc649
FS
436 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
437 @retval Others Operation failed.\r
d933e70a 438**/\r
a35dc649 439EFI_STATUS\r
d933e70a
JW
440HttpBootCacheDhcp4Offer (\r
441 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
442 IN EFI_DHCP4_PACKET *RcvdOffer\r
443 )\r
444{\r
445 HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4;\r
446 EFI_DHCP4_PACKET *Offer;\r
447 HTTP_BOOT_OFFER_TYPE OfferType;\r
a35dc649 448 EFI_STATUS Status;\r
d933e70a
JW
449\r
450 ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM);\r
451 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
452 Offer = &Cache4->Packet.Offer;\r
453\r
454 //\r
455 // Cache the content of DHCPv4 packet firstly.\r
456 //\r
a35dc649
FS
457 Status = HttpBootCacheDhcp4Packet (Offer, RcvdOffer);\r
458 if (EFI_ERROR (Status)) {\r
459 return Status;\r
460 }\r
d933e70a
JW
461\r
462 //\r
463 // Validate the DHCPv4 packet, and parse the options and offer type.\r
464 //\r
465 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) {\r
a35dc649 466 return EFI_ABORTED;\r
d933e70a
JW
467 }\r
468\r
469 //\r
470 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
471 //\r
472 OfferType = Cache4->OfferType;\r
473 ASSERT (OfferType < HttpOfferTypeMax);\r
474 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
475 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
476 Private->OfferCount[OfferType]++;\r
477 Private->OfferNum++;\r
a35dc649
FS
478\r
479 return EFI_SUCCESS;\r
d933e70a
JW
480}\r
481\r
482/**\r
b659408b 483 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
d933e70a
JW
484\r
485 @param[in] Private Pointer to HTTP boot driver private data.\r
486\r
487**/\r
488VOID\r
b659408b 489HttpBootSelectDhcpOffer (\r
d933e70a
JW
490 IN HTTP_BOOT_PRIVATE_DATA *Private\r
491 )\r
492{\r
493 Private->SelectIndex = 0;\r
494 Private->SelectProxyType = HttpOfferTypeMax;\r
fa848a40
FS
495\r
496 if (Private->FilePathUri != NULL) {\r
497 //\r
498 // We are in home environment, the URI is already specified.\r
499 // Just need to choose a DHCP offer.\r
500 // The offer with DNS server address takes priority here.\r
501 //\r
502 if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0) {\r
f75a7f56 503\r
fa848a40 504 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
f75a7f56 505\r
fa848a40 506 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
f75a7f56 507\r
fa848a40 508 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
f75a7f56 509\r
fa848a40 510 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
f75a7f56 511\r
fa848a40 512 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
f75a7f56 513\r
fa848a40 514 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) {\r
f75a7f56 515\r
fa848a40 516 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
f75a7f56 517\r
fa848a40 518 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
f75a7f56 519\r
fa848a40
FS
520 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
521 }\r
f75a7f56 522\r
fa848a40
FS
523 } else {\r
524 //\r
525 // We are in corporate environment.\r
526 //\r
527 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns\r
f75a7f56
LG
528 // Priority2: HttpOfferTypeDhcpNameUriDns\r
529 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri\r
530 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri\r
fa848a40 531 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri\r
f75a7f56
LG
532 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri\r
533 //\r
fa848a40 534 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
f75a7f56 535\r
fa848a40 536 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
f75a7f56 537\r
fa848a40 538 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
f75a7f56 539\r
fa848a40 540 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
f75a7f56 541\r
fa848a40 542 }else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
f75a7f56 543\r
fa848a40 544 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
f75a7f56 545\r
fa848a40
FS
546 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 &&\r
547 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
f75a7f56 548\r
fa848a40
FS
549 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
550 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
f75a7f56 551\r
fa848a40
FS
552 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
553 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
f75a7f56 554\r
fa848a40
FS
555 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
556 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
f75a7f56 557\r
fa848a40
FS
558 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
559 Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) {\r
f75a7f56 560\r
fa848a40
FS
561 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
562 Private->SelectProxyType = HttpOfferTypeProxyNameUri;\r
f75a7f56 563\r
fa848a40
FS
564 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
565 Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) {\r
f75a7f56 566\r
fa848a40
FS
567 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
568 Private->SelectProxyType = HttpOfferTypeDhcpNameUri;\r
569 }\r
d933e70a
JW
570 }\r
571}\r
572\r
573\r
574/**\r
575 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
576 to intercept events that occurred in the configuration process.\r
577\r
578 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
579 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
580 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
581 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
582 state transition.\r
583 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
584 @param[out] NewPacket The packet that is used to replace the above Packet.\r
585\r
586 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
587 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
588 driver will continue to wait for more DHCPOFFER packets until the\r
589 retry timeout expires.\r
590 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
591 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
592\r
593**/\r
594EFI_STATUS\r
595EFIAPI\r
596HttpBootDhcp4CallBack (\r
597 IN EFI_DHCP4_PROTOCOL *This,\r
598 IN VOID *Context,\r
599 IN EFI_DHCP4_STATE CurrentState,\r
600 IN EFI_DHCP4_EVENT Dhcp4Event,\r
601 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
602 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
603 )\r
604{\r
605 HTTP_BOOT_PRIVATE_DATA *Private;\r
606 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
607 UINT16 Value;\r
608 EFI_STATUS Status;\r
95b5c32f 609 BOOLEAN Received;\r
d933e70a 610\r
f75a7f56
LG
611 if ((Dhcp4Event != Dhcp4SendDiscover) &&\r
612 (Dhcp4Event != Dhcp4RcvdOffer) &&\r
613 (Dhcp4Event != Dhcp4SendRequest) &&\r
614 (Dhcp4Event != Dhcp4RcvdAck) &&\r
95b5c32f 615 (Dhcp4Event != Dhcp4SelectOffer)) {\r
d933e70a
JW
616 return EFI_SUCCESS;\r
617 }\r
f75a7f56 618\r
d933e70a
JW
619 Private = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
620\r
621 //\r
622 // Override the Maximum DHCP Message Size.\r
623 //\r
624 MaxMsgSize = HttpBootParseDhcp4Options (\r
625 Packet->Dhcp4.Option,\r
626 GET_OPTION_BUFFER_LEN (Packet),\r
142c00c3 627 DHCP4_TAG_MAXMSG\r
d933e70a
JW
628 );\r
629 if (MaxMsgSize != NULL) {\r
630 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);\r
631 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
632 }\r
f75a7f56 633\r
95b5c32f
FS
634 //\r
635 // Callback to user if any packets sent or received.\r
636 //\r
637 if (Private->HttpBootCallback != NULL && Dhcp4Event != Dhcp4SelectOffer) {\r
638 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);\r
639 Status = Private->HttpBootCallback->Callback (\r
f75a7f56 640 Private->HttpBootCallback,\r
95b5c32f
FS
641 HttpBootDhcp4,\r
642 Received,\r
643 Packet->Length,\r
644 &Packet->Dhcp4\r
645 );\r
646 if (EFI_ERROR (Status)) {\r
647 return EFI_ABORTED;\r
648 }\r
649 }\r
d933e70a
JW
650\r
651 Status = EFI_SUCCESS;\r
652 switch (Dhcp4Event) {\r
653 case Dhcp4RcvdOffer:\r
654 Status = EFI_NOT_READY;\r
a35dc649
FS
655 if (Packet->Length > HTTP_BOOT_DHCP4_PACKET_MAX_SIZE) {\r
656 //\r
657 // Ignore the incoming packets which exceed the maximum length.\r
658 //\r
659 break;\r
660 }\r
d933e70a
JW
661 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
662 //\r
663 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
664 // the OfferIndex and OfferCount.\r
a35dc649 665 // If error happens, just ignore this packet and continue to wait more offer.\r
d933e70a
JW
666 //\r
667 HttpBootCacheDhcp4Offer (Private, Packet);\r
668 }\r
669 break;\r
670\r
671 case Dhcp4SelectOffer:\r
672 //\r
f75a7f56 673 // Select offer according to the priority in UEFI spec, and record the SelectIndex\r
d933e70a
JW
674 // and SelectProxyType.\r
675 //\r
b659408b 676 HttpBootSelectDhcpOffer (Private);\r
d933e70a
JW
677\r
678 if (Private->SelectIndex == 0) {\r
679 Status = EFI_ABORTED;\r
680 } else {\r
681 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
682 }\r
683 break;\r
f75a7f56 684\r
d933e70a
JW
685 default:\r
686 break;\r
687 }\r
688\r
689 return Status;\r
690}\r
691\r
692/**\r
693 This function will register the IPv4 gateway address to the network device.\r
f75a7f56 694\r
d933e70a
JW
695 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
696\r
697 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
698 @retval Others Failed to configure the address.\r
699\r
700**/\r
701EFI_STATUS\r
702HttpBootRegisterIp4Gateway (\r
703 IN HTTP_BOOT_PRIVATE_DATA *Private\r
704 )\r
705{\r
706 EFI_STATUS Status;\r
707 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
708\r
709 ASSERT (!Private->UsingIpv6);\r
710\r
711 Ip4Config2 = Private->Ip4Config2;\r
712\r
713 //\r
714 // Configure the gateway if valid.\r
715 //\r
716 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {\r
717 Status = Ip4Config2->SetData (\r
718 Ip4Config2,\r
719 Ip4Config2DataTypeGateway,\r
720 sizeof (EFI_IPv4_ADDRESS),\r
721 &Private->GatewayIp\r
722 );\r
723 if (EFI_ERROR (Status)) {\r
724 return Status;\r
725 }\r
726 }\r
727\r
728 return EFI_SUCCESS;\r
729}\r
730\r
731/**\r
732 This function will register the default DNS addresses to the network device.\r
f75a7f56 733\r
d933e70a
JW
734 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
735 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
736 @param[in] DnsServerData Point a list of DNS server address in an array\r
737 of EFI_IPv4_ADDRESS instances.\r
738\r
739 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
740 @retval Others Failed to configure the address.\r
741\r
742**/\r
743EFI_STATUS\r
744HttpBootRegisterIp4Dns (\r
745 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
746 IN UINTN DataLength,\r
747 IN VOID *DnsServerData\r
748 )\r
749{\r
750 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
f75a7f56 751\r
d933e70a
JW
752 ASSERT (!Private->UsingIpv6);\r
753\r
754 Ip4Config2 = Private->Ip4Config2;\r
f75a7f56 755\r
d933e70a
JW
756 return Ip4Config2->SetData (\r
757 Ip4Config2,\r
758 Ip4Config2DataTypeDnsServer,\r
759 DataLength,\r
760 DnsServerData\r
761 );\r
762}\r
763\r
764\r
765/**\r
766 This function will switch the IP4 configuration policy to Static.\r
767\r
768 @param[in] Private Pointer to HTTP boot driver private data.\r
769\r
770 @retval EFI_SUCCESS The policy is already configured to static.\r
771 @retval Others Other error as indicated..\r
772\r
773**/\r
774EFI_STATUS\r
b659408b 775HttpBootSetIp4Policy (\r
d933e70a
JW
776 IN HTTP_BOOT_PRIVATE_DATA *Private\r
777 )\r
778{\r
779 EFI_IP4_CONFIG2_POLICY Policy;\r
780 EFI_STATUS Status;\r
781 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
782 UINTN DataSize;\r
783\r
784 Ip4Config2 = Private->Ip4Config2;\r
785\r
786 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
787 Status = Ip4Config2->GetData (\r
788 Ip4Config2,\r
789 Ip4Config2DataTypePolicy,\r
790 &DataSize,\r
791 &Policy\r
792 );\r
793 if (EFI_ERROR (Status)) {\r
794 return Status;\r
795 }\r
796\r
797 if (Policy != Ip4Config2PolicyStatic) {\r
798 Policy = Ip4Config2PolicyStatic;\r
799 Status= Ip4Config2->SetData (\r
800 Ip4Config2,\r
801 Ip4Config2DataTypePolicy,\r
802 sizeof (EFI_IP4_CONFIG2_POLICY),\r
803 &Policy\r
804 );\r
805 if (EFI_ERROR (Status)) {\r
806 return Status;\r
f75a7f56 807 }\r
d933e70a
JW
808 }\r
809\r
810 return EFI_SUCCESS;\r
811}\r
812\r
813/**\r
814 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
815\r
816 @param[in] Private Pointer to HTTP boot driver private data.\r
817\r
818 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
819 @retval Others Failed to finish the D.O.R.A process.\r
820\r
821**/\r
822EFI_STATUS\r
823HttpBootDhcp4Dora (\r
824 IN HTTP_BOOT_PRIVATE_DATA *Private\r
825 )\r
826{\r
827 EFI_DHCP4_PROTOCOL *Dhcp4;\r
828 UINT32 OptCount;\r
829 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];\r
830 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];\r
831 EFI_DHCP4_CONFIG_DATA Config;\r
832 EFI_STATUS Status;\r
833 EFI_DHCP4_MODE_DATA Mode;\r
f75a7f56 834\r
d933e70a
JW
835 Dhcp4 = Private->Dhcp4;\r
836 ASSERT (Dhcp4 != NULL);\r
837\r
b659408b 838 Status = HttpBootSetIp4Policy (Private);\r
d933e70a
JW
839 if (EFI_ERROR (Status)) {\r
840 return Status;\r
841 }\r
842\r
843 //\r
844 // Build option list for the request packet.\r
845 //\r
846 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);\r
847 ASSERT (OptCount > 0);\r
848\r
849 ZeroMem (&Config, sizeof(Config));\r
850 Config.OptionCount = OptCount;\r
851 Config.OptionList = OptList;\r
852 Config.Dhcp4Callback = HttpBootDhcp4CallBack;\r
853 Config.CallbackContext = Private;\r
854 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;\r
855 Config.DiscoverTimeout = mHttpDhcpTimeout;\r
856\r
857 //\r
858 // Configure the DHCPv4 instance for HTTP boot.\r
859 //\r
860 Status = Dhcp4->Configure (Dhcp4, &Config);\r
861 if (EFI_ERROR (Status)) {\r
862 goto ON_EXIT;\r
863 }\r
864\r
865 //\r
866 // Initialize the record fields for DHCPv4 offer in private data.\r
867 //\r
868 Private->OfferNum = 0;\r
869 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
870 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
871\r
872 //\r
873 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.\r
874 //\r
875 Status = Dhcp4->Start (Dhcp4, NULL);\r
876 if (EFI_ERROR (Status)) {\r
877 goto ON_EXIT;\r
878 }\r
879\r
880 //\r
881 // Get the acquired IPv4 address and store them.\r
882 //\r
883 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
884 if (EFI_ERROR (Status)) {\r
885 goto ON_EXIT;\r
886 }\r
887\r
888 ASSERT (Mode.State == Dhcp4Bound);\r
889 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
890 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
891 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
892\r
893 Status = HttpBootRegisterIp4Gateway (Private);\r
894 if (EFI_ERROR (Status)) {\r
895 goto ON_EXIT;\r
896 }\r
897\r
898 AsciiPrint ("\n Station IP address is ");\r
899 HttpBootShowIp4Addr (&Private->StationIp.v4);\r
900 AsciiPrint ("\n");\r
901\r
902ON_EXIT:\r
903 if (EFI_ERROR (Status)) {\r
904 Dhcp4->Stop (Dhcp4);\r
905 Dhcp4->Configure (Dhcp4, NULL);\r
906 } else {\r
907 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
908 Dhcp4->Configure (Dhcp4, &Config);\r
909 }\r
910\r
911 return Status;\r
912}\r