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