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