]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
MdeModulePkg: Ignore BootFileName if it is overloaded.
[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
262 \r
263 IsDnsOffer = FALSE;\r
264 IpExpressedUri = FALSE;\r
265 IsProxyOffer = FALSE;\r
266 IsHttpOffer = FALSE;\r
267\r
268 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));\r
269\r
270 Offer = &Cache4->Packet.Offer;\r
271 Options = Cache4->OptList;\r
272\r
273 //\r
274 // Parse DHCPv4 options in this offer, and store the pointers.\r
275 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
276 //\r
277 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
278 Options[Index] = HttpBootParseDhcp4Options (\r
279 Offer->Dhcp4.Option,\r
280 GET_OPTION_BUFFER_LEN (Offer),\r
281 mInterestedDhcp4Tags[Index]\r
282 );\r
283 }\r
284 //\r
285 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. \r
286 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
287 //\r
288 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD];\r
289 if (Option != NULL) {\r
290 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) {\r
291 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
292 if (Options[Index] == NULL) {\r
293 Options[Index] = HttpBootParseDhcp4Options (\r
294 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
295 sizeof (Offer->Dhcp4.Header.BootFileName),\r
296 mInterestedDhcp4Tags[Index]\r
297 );\r
298 }\r
299 }\r
300 }\r
301 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
302 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
303 if (Options[Index] == NULL) {\r
304 Options[Index] = HttpBootParseDhcp4Options (\r
305 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
306 sizeof (Offer->Dhcp4.Header.ServerName),\r
307 mInterestedDhcp4Tags[Index]\r
308 );\r
309 }\r
310 }\r
311 }\r
312 }\r
313\r
314 //\r
315 // The offer with "yiaddr" is a proxy offer.\r
316 //\r
317 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
318 IsProxyOffer = TRUE;\r
319 }\r
320\r
321 //\r
b659408b 322 // The offer with "HTTPClient" is a Http offer.\r
d933e70a
JW
323 //\r
324 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];\r
325 if ((Option != NULL) && (Option->Length >= 9) &&\r
326 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
327 IsHttpOffer = TRUE;\r
328 }\r
329\r
330 //\r
331 // The offer with Domain Server is a DNS offer.\r
332 //\r
333 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];\r
334 if (Option != NULL) {\r
335 IsDnsOffer = TRUE;\r
336 }\r
337\r
338 //\r
339 // Parse boot file name:\r
340 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.\r
341 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
342 // Otherwise, read from boot file field in DHCP header.\r
343 //\r
344 if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
345 //\r
346 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
347 // terminated string. So force to append null terminated character at the end of string.\r
348 //\r
349 Ptr8 = (UINT8*)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
350 Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
351 if (*(Ptr8 - 1) != '\0') {\r
352 *Ptr8 = '\0';\r
353 }\r
354 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
355 //\r
356 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
357 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
358 //\r
359 Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
360 (&Offer->Dhcp4.Header.BootFileName[0] -\r
361 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
362 }\r
363\r
364 //\r
365 // Http offer must have a boot URI.\r
366 //\r
367 if (IsHttpOffer && Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
368 return EFI_DEVICE_ERROR;\r
369 }\r
370\r
371 //\r
372 // Try to retrieve the IP of HTTP server from URI. \r
373 //\r
374 if (IsHttpOffer) {\r
375 Status = HttpParseUrl (\r
376 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
377 (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data),\r
378 FALSE,\r
379 &Cache4->UriParser\r
380 );\r
381 if (EFI_ERROR (Status)) {\r
382 return EFI_DEVICE_ERROR;\r
383 }\r
384\r
385 Status = HttpUrlGetIp4 (\r
386 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
387 Cache4->UriParser,\r
388 &IpAddr\r
389 );\r
390 IpExpressedUri = !EFI_ERROR (Status);\r
391 }\r
392\r
393 //\r
394 // Determine offer type of the DHCPv4 packet.\r
395 //\r
396 if (IsHttpOffer) {\r
397 if (IpExpressedUri) {\r
fa848a40
FS
398 if (IsProxyOffer) {\r
399 OfferType = HttpOfferTypeProxyIpUri;\r
400 } else {\r
401 OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;\r
402 }\r
d933e70a
JW
403 } else {\r
404 if (!IsProxyOffer) {\r
405 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
406 } else {\r
407 OfferType = HttpOfferTypeProxyNameUri;\r
408 }\r
409 }\r
410\r
411 } else {\r
412 if (!IsProxyOffer) {\r
413 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
414 } else {\r
415 return EFI_DEVICE_ERROR;\r
416 }\r
417 }\r
418 \r
419 Cache4->OfferType = OfferType;\r
420 return EFI_SUCCESS;\r
421}\r
422\r
423/**\r
424 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
425\r
426 @param[in] Private Pointer to HTTP boot driver private data.\r
427 @param[in] RcvdOffer Pointer to the received offer packet.\r
428\r
429**/\r
430VOID\r
431HttpBootCacheDhcp4Offer (\r
432 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
433 IN EFI_DHCP4_PACKET *RcvdOffer\r
434 )\r
435{\r
436 HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4;\r
437 EFI_DHCP4_PACKET *Offer;\r
438 HTTP_BOOT_OFFER_TYPE OfferType;\r
439\r
440 ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM);\r
441 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
442 Offer = &Cache4->Packet.Offer;\r
443\r
444 //\r
445 // Cache the content of DHCPv4 packet firstly.\r
446 //\r
447 HttpBootCacheDhcp4Packet (Offer, RcvdOffer);\r
448\r
449 //\r
450 // Validate the DHCPv4 packet, and parse the options and offer type.\r
451 //\r
452 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) {\r
453 return;\r
454 }\r
455\r
456 //\r
457 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
458 //\r
459 OfferType = Cache4->OfferType;\r
460 ASSERT (OfferType < HttpOfferTypeMax);\r
461 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
462 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
463 Private->OfferCount[OfferType]++;\r
464 Private->OfferNum++;\r
465}\r
466\r
467/**\r
b659408b 468 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
d933e70a
JW
469\r
470 @param[in] Private Pointer to HTTP boot driver private data.\r
471\r
472**/\r
473VOID\r
b659408b 474HttpBootSelectDhcpOffer (\r
d933e70a
JW
475 IN HTTP_BOOT_PRIVATE_DATA *Private\r
476 )\r
477{\r
478 Private->SelectIndex = 0;\r
479 Private->SelectProxyType = HttpOfferTypeMax;\r
fa848a40
FS
480\r
481 if (Private->FilePathUri != NULL) {\r
482 //\r
483 // We are in home environment, the URI is already specified.\r
484 // Just need to choose a DHCP offer.\r
485 // The offer with DNS server address takes priority here.\r
486 //\r
487 if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0) {\r
488 \r
489 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
490 \r
491 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
d933e70a 492 \r
fa848a40
FS
493 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
494 \r
495 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
d933e70a 496 \r
fa848a40
FS
497 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
498 \r
499 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) {\r
d933e70a 500 \r
fa848a40
FS
501 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
502 \r
503 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
d933e70a 504 \r
fa848a40
FS
505 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
506 }\r
d933e70a 507 \r
fa848a40
FS
508 } else {\r
509 //\r
510 // We are in corporate environment.\r
511 //\r
512 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns\r
513 // Priority2: HttpOfferTypeDhcpNameUriDns \r
514 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri \r
515 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri \r
516 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri\r
517 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri \r
518 // \r
519 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
520 \r
521 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
522 \r
523 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
524 \r
525 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
526 \r
527 }else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
d933e70a 528 \r
fa848a40
FS
529 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
530 \r
531 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 &&\r
532 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
533 \r
534 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
535 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
536 \r
537 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
538 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
539 \r
540 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
541 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
542 \r
543 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
544 Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) {\r
545 \r
546 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
547 Private->SelectProxyType = HttpOfferTypeProxyNameUri;\r
548 \r
549 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
550 Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) {\r
551 \r
552 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
553 Private->SelectProxyType = HttpOfferTypeDhcpNameUri;\r
554 }\r
d933e70a
JW
555 }\r
556}\r
557\r
558\r
559/**\r
560 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
561 to intercept events that occurred in the configuration process.\r
562\r
563 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
564 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
565 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
566 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
567 state transition.\r
568 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
569 @param[out] NewPacket The packet that is used to replace the above Packet.\r
570\r
571 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
572 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
573 driver will continue to wait for more DHCPOFFER packets until the\r
574 retry timeout expires.\r
575 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
576 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
577\r
578**/\r
579EFI_STATUS\r
580EFIAPI\r
581HttpBootDhcp4CallBack (\r
582 IN EFI_DHCP4_PROTOCOL *This,\r
583 IN VOID *Context,\r
584 IN EFI_DHCP4_STATE CurrentState,\r
585 IN EFI_DHCP4_EVENT Dhcp4Event,\r
586 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
587 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
588 )\r
589{\r
590 HTTP_BOOT_PRIVATE_DATA *Private;\r
591 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
592 UINT16 Value;\r
593 EFI_STATUS Status;\r
594\r
595 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
596 return EFI_SUCCESS;\r
597 }\r
598 \r
599 Private = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
600\r
601 //\r
602 // Override the Maximum DHCP Message Size.\r
603 //\r
604 MaxMsgSize = HttpBootParseDhcp4Options (\r
605 Packet->Dhcp4.Option,\r
606 GET_OPTION_BUFFER_LEN (Packet),\r
607 HTTP_BOOT_DHCP4_TAG_MAXMSG\r
608 );\r
609 if (MaxMsgSize != NULL) {\r
610 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);\r
611 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
612 }\r
613\r
614 Status = EFI_SUCCESS;\r
615 switch (Dhcp4Event) {\r
616 case Dhcp4RcvdOffer:\r
617 Status = EFI_NOT_READY;\r
618 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
619 //\r
620 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
621 // the OfferIndex and OfferCount.\r
622 //\r
623 HttpBootCacheDhcp4Offer (Private, Packet);\r
624 }\r
625 break;\r
626\r
627 case Dhcp4SelectOffer:\r
628 //\r
629 // Select offer according to the priority in UEFI spec, and record the SelectIndex \r
630 // and SelectProxyType.\r
631 //\r
b659408b 632 HttpBootSelectDhcpOffer (Private);\r
d933e70a
JW
633\r
634 if (Private->SelectIndex == 0) {\r
635 Status = EFI_ABORTED;\r
636 } else {\r
637 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
638 }\r
639 break;\r
640 \r
641 default:\r
642 break;\r
643 }\r
644\r
645 return Status;\r
646}\r
647\r
648/**\r
649 This function will register the IPv4 gateway address to the network device.\r
650 \r
651 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
652\r
653 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
654 @retval Others Failed to configure the address.\r
655\r
656**/\r
657EFI_STATUS\r
658HttpBootRegisterIp4Gateway (\r
659 IN HTTP_BOOT_PRIVATE_DATA *Private\r
660 )\r
661{\r
662 EFI_STATUS Status;\r
663 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
664\r
665 ASSERT (!Private->UsingIpv6);\r
666\r
667 Ip4Config2 = Private->Ip4Config2;\r
668\r
669 //\r
670 // Configure the gateway if valid.\r
671 //\r
672 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {\r
673 Status = Ip4Config2->SetData (\r
674 Ip4Config2,\r
675 Ip4Config2DataTypeGateway,\r
676 sizeof (EFI_IPv4_ADDRESS),\r
677 &Private->GatewayIp\r
678 );\r
679 if (EFI_ERROR (Status)) {\r
680 return Status;\r
681 }\r
682 }\r
683\r
684 return EFI_SUCCESS;\r
685}\r
686\r
687/**\r
688 This function will register the default DNS addresses to the network device.\r
689 \r
690 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
691 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
692 @param[in] DnsServerData Point a list of DNS server address in an array\r
693 of EFI_IPv4_ADDRESS instances.\r
694\r
695 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
696 @retval Others Failed to configure the address.\r
697\r
698**/\r
699EFI_STATUS\r
700HttpBootRegisterIp4Dns (\r
701 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
702 IN UINTN DataLength,\r
703 IN VOID *DnsServerData\r
704 )\r
705{\r
706 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
707 \r
708 ASSERT (!Private->UsingIpv6);\r
709\r
710 Ip4Config2 = Private->Ip4Config2;\r
711 \r
712 return Ip4Config2->SetData (\r
713 Ip4Config2,\r
714 Ip4Config2DataTypeDnsServer,\r
715 DataLength,\r
716 DnsServerData\r
717 );\r
718}\r
719\r
720\r
721/**\r
722 This function will switch the IP4 configuration policy to Static.\r
723\r
724 @param[in] Private Pointer to HTTP boot driver private data.\r
725\r
726 @retval EFI_SUCCESS The policy is already configured to static.\r
727 @retval Others Other error as indicated..\r
728\r
729**/\r
730EFI_STATUS\r
b659408b 731HttpBootSetIp4Policy (\r
d933e70a
JW
732 IN HTTP_BOOT_PRIVATE_DATA *Private\r
733 )\r
734{\r
735 EFI_IP4_CONFIG2_POLICY Policy;\r
736 EFI_STATUS Status;\r
737 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
738 UINTN DataSize;\r
739\r
740 Ip4Config2 = Private->Ip4Config2;\r
741\r
742 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
743 Status = Ip4Config2->GetData (\r
744 Ip4Config2,\r
745 Ip4Config2DataTypePolicy,\r
746 &DataSize,\r
747 &Policy\r
748 );\r
749 if (EFI_ERROR (Status)) {\r
750 return Status;\r
751 }\r
752\r
753 if (Policy != Ip4Config2PolicyStatic) {\r
754 Policy = Ip4Config2PolicyStatic;\r
755 Status= Ip4Config2->SetData (\r
756 Ip4Config2,\r
757 Ip4Config2DataTypePolicy,\r
758 sizeof (EFI_IP4_CONFIG2_POLICY),\r
759 &Policy\r
760 );\r
761 if (EFI_ERROR (Status)) {\r
762 return Status;\r
763 } \r
764 }\r
765\r
766 return EFI_SUCCESS;\r
767}\r
768\r
769/**\r
770 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
771\r
772 @param[in] Private Pointer to HTTP boot driver private data.\r
773\r
774 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
775 @retval Others Failed to finish the D.O.R.A process.\r
776\r
777**/\r
778EFI_STATUS\r
779HttpBootDhcp4Dora (\r
780 IN HTTP_BOOT_PRIVATE_DATA *Private\r
781 )\r
782{\r
783 EFI_DHCP4_PROTOCOL *Dhcp4;\r
784 UINT32 OptCount;\r
785 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];\r
786 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];\r
787 EFI_DHCP4_CONFIG_DATA Config;\r
788 EFI_STATUS Status;\r
789 EFI_DHCP4_MODE_DATA Mode;\r
790 \r
791 Dhcp4 = Private->Dhcp4;\r
792 ASSERT (Dhcp4 != NULL);\r
793\r
b659408b 794 Status = HttpBootSetIp4Policy (Private);\r
d933e70a
JW
795 if (EFI_ERROR (Status)) {\r
796 return Status;\r
797 }\r
798\r
799 //\r
800 // Build option list for the request packet.\r
801 //\r
802 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);\r
803 ASSERT (OptCount > 0);\r
804\r
805 ZeroMem (&Config, sizeof(Config));\r
806 Config.OptionCount = OptCount;\r
807 Config.OptionList = OptList;\r
808 Config.Dhcp4Callback = HttpBootDhcp4CallBack;\r
809 Config.CallbackContext = Private;\r
810 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;\r
811 Config.DiscoverTimeout = mHttpDhcpTimeout;\r
812\r
813 //\r
814 // Configure the DHCPv4 instance for HTTP boot.\r
815 //\r
816 Status = Dhcp4->Configure (Dhcp4, &Config);\r
817 if (EFI_ERROR (Status)) {\r
818 goto ON_EXIT;\r
819 }\r
820\r
821 //\r
822 // Initialize the record fields for DHCPv4 offer in private data.\r
823 //\r
824 Private->OfferNum = 0;\r
825 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
826 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
827\r
828 //\r
829 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.\r
830 //\r
831 Status = Dhcp4->Start (Dhcp4, NULL);\r
832 if (EFI_ERROR (Status)) {\r
833 goto ON_EXIT;\r
834 }\r
835\r
836 //\r
837 // Get the acquired IPv4 address and store them.\r
838 //\r
839 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
840 if (EFI_ERROR (Status)) {\r
841 goto ON_EXIT;\r
842 }\r
843\r
844 ASSERT (Mode.State == Dhcp4Bound);\r
845 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
846 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
847 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
848\r
849 Status = HttpBootRegisterIp4Gateway (Private);\r
850 if (EFI_ERROR (Status)) {\r
851 goto ON_EXIT;\r
852 }\r
853\r
854 AsciiPrint ("\n Station IP address is ");\r
855 HttpBootShowIp4Addr (&Private->StationIp.v4);\r
856 AsciiPrint ("\n");\r
857\r
858ON_EXIT:\r
859 if (EFI_ERROR (Status)) {\r
860 Dhcp4->Stop (Dhcp4);\r
861 Dhcp4->Configure (Dhcp4, NULL);\r
862 } else {\r
863 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
864 Dhcp4->Configure (Dhcp4, &Config);\r
865 }\r
866\r
867 return Status;\r
868}\r