]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
NetworkPkg: Apply uncrustify changes
[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
d1050b9d 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
d1050b9d 27UINT32 mHttpDhcpTimeout[4] = { 4, 8, 16, 32 };\r
d933e70a
JW
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
d1050b9d
MK
41 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
42 OUT EFI_DHCP4_PACKET_OPTION **OptList,\r
43 IN UINT8 *Buffer\r
d933e70a
JW
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
d1050b9d 51 OptList[0] = (EFI_DHCP4_PACKET_OPTION *)Buffer;\r
d933e70a
JW
52\r
53 //\r
54 // Append parameter request list option.\r
55 //\r
142c00c3 56 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;\r
d933e70a 57 OptList[Index]->Length = 27;\r
d1050b9d 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 85 Index++;\r
d1050b9d 86 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
d933e70a
JW
87\r
88 //\r
89 // Append UUID/Guid-based client identifier option\r
90 //\r
d1050b9d
MK
91 OptList[Index]->OpCode = DHCP4_TAG_UUID;\r
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
d933e70a 96 //\r
c36b7b51 97 // Zero the Guid to indicate NOT programmable if failed to get system Guid.\r
d933e70a
JW
98 //\r
99 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
100 }\r
d1050b9d 101\r
d933e70a 102 Index++;\r
d1050b9d 103 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
d933e70a
JW
104\r
105 //\r
106 // Append client network device interface option\r
107 //\r
d1050b9d
MK
108 OptList[Index]->OpCode = DHCP4_TAG_UNDI;\r
109 OptList[Index]->Length = (UINT8)sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI);\r
110 OptEnt.Undi = (HTTP_BOOT_DHCP4_OPTION_UNDI *)OptList[Index]->Data;\r
d933e70a
JW
111\r
112 if (Private->Nii != NULL) {\r
113 OptEnt.Undi->Type = Private->Nii->Type;\r
114 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
115 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
116 } else {\r
117 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
118 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
119 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
120 }\r
121\r
122 Index++;\r
123 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
124\r
125 //\r
126 // Append client system architecture option\r
127 //\r
d1050b9d
MK
128 OptList[Index]->OpCode = DHCP4_TAG_ARCH;\r
129 OptList[Index]->Length = (UINT8)sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH);\r
130 OptEnt.Arch = (HTTP_BOOT_DHCP4_OPTION_ARCH *)OptList[Index]->Data;\r
131 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);\r
d933e70a
JW
132 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
133 Index++;\r
d1050b9d 134 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
d933e70a
JW
135\r
136 //\r
137 // Append vendor class identify option\r
138 //\r
d1050b9d
MK
139 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;\r
140 OptList[Index]->Length = (UINT8)sizeof (HTTP_BOOT_DHCP4_OPTION_CLID);\r
141 OptEnt.Clid = (HTTP_BOOT_DHCP4_OPTION_CLID *)OptList[Index]->Data;\r
d933e70a
JW
142 CopyMem (\r
143 OptEnt.Clid,\r
144 DEFAULT_CLASS_ID_DATA,\r
145 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID)\r
146 );\r
147 HttpBootUintnToAscDecWithFormat (\r
148 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,\r
149 OptEnt.Clid->ArchitectureType,\r
150 sizeof (OptEnt.Clid->ArchitectureType)\r
151 );\r
152\r
153 if (Private->Nii != NULL) {\r
154 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
155 HttpBootUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
156 HttpBootUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
157 }\r
158\r
159 Index++;\r
160\r
161 return Index;\r
162}\r
163\r
164/**\r
165 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.\r
166\r
167 @param[in] Buffer Pointer to the option buffer.\r
168 @param[in] Length Length of the option buffer.\r
169 @param[in] OptTag Tag of the required option.\r
170\r
171 @retval NULL Failed to find the required option.\r
172 @retval Others The position of the required option.\r
173\r
174**/\r
175EFI_DHCP4_PACKET_OPTION *\r
176HttpBootParseDhcp4Options (\r
d1050b9d
MK
177 IN UINT8 *Buffer,\r
178 IN UINT32 Length,\r
179 IN UINT8 OptTag\r
d933e70a
JW
180 )\r
181{\r
d1050b9d
MK
182 EFI_DHCP4_PACKET_OPTION *Option;\r
183 UINT32 Offset;\r
d933e70a 184\r
d1050b9d
MK
185 Option = (EFI_DHCP4_PACKET_OPTION *)Buffer;\r
186 Offset = 0;\r
d933e70a 187\r
142c00c3 188 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {\r
d933e70a
JW
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
d1050b9d 205 Option = (EFI_DHCP4_PACKET_OPTION *)(Buffer + Offset);\r
d933e70a
JW
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 222HttpBootCacheDhcp4Packet (\r
d1050b9d
MK
223 IN EFI_DHCP4_PACKET *Dst,\r
224 IN EFI_DHCP4_PACKET *Src\r
d933e70a
JW
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
d1050b9d 248 IN HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4\r
d933e70a
JW
249 )\r
250{\r
d1050b9d
MK
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
263 BOOLEAN FileFieldOverloaded;\r
264\r
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
d1050b9d 287\r
d933e70a 288 //\r
f75a7f56 289 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.\r
d933e70a
JW
290 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
291 //\r
292 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD];\r
293 if (Option != NULL) {\r
294 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) {\r
b7f28e1a 295 FileFieldOverloaded = TRUE;\r
d933e70a
JW
296 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
297 if (Options[Index] == NULL) {\r
298 Options[Index] = HttpBootParseDhcp4Options (\r
d1050b9d 299 (UINT8 *)Offer->Dhcp4.Header.BootFileName,\r
d933e70a
JW
300 sizeof (Offer->Dhcp4.Header.BootFileName),\r
301 mInterestedDhcp4Tags[Index]\r
302 );\r
303 }\r
304 }\r
305 }\r
d1050b9d 306\r
d933e70a
JW
307 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
308 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
309 if (Options[Index] == NULL) {\r
310 Options[Index] = HttpBootParseDhcp4Options (\r
d1050b9d 311 (UINT8 *)Offer->Dhcp4.Header.ServerName,\r
d933e70a
JW
312 sizeof (Offer->Dhcp4.Header.ServerName),\r
313 mInterestedDhcp4Tags[Index]\r
314 );\r
315 }\r
316 }\r
317 }\r
318 }\r
319\r
320 //\r
321 // The offer with "yiaddr" is a proxy offer.\r
322 //\r
323 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
324 IsProxyOffer = TRUE;\r
325 }\r
326\r
327 //\r
b659408b 328 // The offer with "HTTPClient" is a Http offer.\r
d933e70a
JW
329 //\r
330 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];\r
1ba4a4df 331 if ((Option != NULL) && (Option->Length >= 10) &&\r
d1050b9d
MK
332 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 0))\r
333 {\r
d933e70a
JW
334 IsHttpOffer = TRUE;\r
335 }\r
336\r
337 //\r
338 // The offer with Domain Server is a DNS offer.\r
339 //\r
340 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];\r
341 if (Option != NULL) {\r
342 IsDnsOffer = TRUE;\r
343 }\r
344\r
345 //\r
346 // Parse boot file name:\r
347 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.\r
348 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
349 // Otherwise, read from boot file field in DHCP header.\r
350 //\r
351 if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
352 //\r
353 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
354 // terminated string. So force to append null terminated character at the end of string.\r
355 //\r
d1050b9d 356 Ptr8 = (UINT8 *)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
d933e70a
JW
357 Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
358 if (*(Ptr8 - 1) != '\0') {\r
359 *Ptr8 = '\0';\r
360 }\r
d1050b9d 361 } else if (!FileFieldOverloaded && (Offer->Dhcp4.Header.BootFileName[0] != 0)) {\r
d933e70a
JW
362 //\r
363 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
364 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
365 //\r
366 Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
d1050b9d
MK
367 (&Offer->Dhcp4.Header.BootFileName[0] -\r
368 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
d933e70a
JW
369 }\r
370\r
371 //\r
372 // Http offer must have a boot URI.\r
373 //\r
d1050b9d 374 if (IsHttpOffer && (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL)) {\r
d933e70a
JW
375 return EFI_DEVICE_ERROR;\r
376 }\r
377\r
378 //\r
f75a7f56 379 // Try to retrieve the IP of HTTP server from URI.\r
d933e70a
JW
380 //\r
381 if (IsHttpOffer) {\r
382 Status = HttpParseUrl (\r
d1050b9d
MK
383 (CHAR8 *)Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
384 (UINT32)AsciiStrLen ((CHAR8 *)Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data),\r
d933e70a
JW
385 FALSE,\r
386 &Cache4->UriParser\r
387 );\r
388 if (EFI_ERROR (Status)) {\r
389 return EFI_DEVICE_ERROR;\r
390 }\r
391\r
392 Status = HttpUrlGetIp4 (\r
d1050b9d 393 (CHAR8 *)Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
d933e70a
JW
394 Cache4->UriParser,\r
395 &IpAddr\r
396 );\r
397 IpExpressedUri = !EFI_ERROR (Status);\r
398 }\r
399\r
400 //\r
401 // Determine offer type of the DHCPv4 packet.\r
402 //\r
403 if (IsHttpOffer) {\r
404 if (IpExpressedUri) {\r
fa848a40
FS
405 if (IsProxyOffer) {\r
406 OfferType = HttpOfferTypeProxyIpUri;\r
407 } else {\r
408 OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;\r
409 }\r
d933e70a
JW
410 } else {\r
411 if (!IsProxyOffer) {\r
412 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
413 } else {\r
414 OfferType = HttpOfferTypeProxyNameUri;\r
415 }\r
416 }\r
d933e70a
JW
417 } else {\r
418 if (!IsProxyOffer) {\r
419 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
420 } else {\r
0dc59296
JW
421 if (Cache4->UriParser != NULL) {\r
422 FreePool (Cache4->UriParser);\r
423 }\r
d1050b9d 424\r
d933e70a
JW
425 return EFI_DEVICE_ERROR;\r
426 }\r
427 }\r
f75a7f56 428\r
d933e70a
JW
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
d1050b9d 496 Private->SelectIndex = 0;\r
d933e70a 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
fa848a40 506 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
fa848a40 507 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
fa848a40 508 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
fa848a40 509 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
fa848a40 510 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
d1050b9d 511 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) {\r
fa848a40 512 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
d1050b9d 513 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
fa848a40
FS
514 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
515 }\r
fa848a40
FS
516 } else {\r
517 //\r
518 // We are in corporate environment.\r
519 //\r
520 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns\r
f75a7f56
LG
521 // Priority2: HttpOfferTypeDhcpNameUriDns\r
522 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri\r
523 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri\r
fa848a40 524 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri\r
f75a7f56
LG
525 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri\r
526 //\r
fa848a40 527 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
fa848a40 528 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
fa848a40 529 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
fa848a40 530 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
d1050b9d 531 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
fa848a40 532 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
d1050b9d
MK
533 } else if ((Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) &&\r
534 (Private->OfferCount[HttpOfferTypeProxyIpUri] > 0))\r
535 {\r
fa848a40
FS
536 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
537 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
d1050b9d
MK
538 } else if ((Private->OfferCount[HttpOfferTypeDhcpDns] > 0) &&\r
539 (Private->OfferCount[HttpOfferTypeProxyIpUri] > 0))\r
540 {\r
fa848a40
FS
541 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
542 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
d1050b9d
MK
543 } else if ((Private->OfferCount[HttpOfferTypeDhcpDns] > 0) &&\r
544 (Private->OfferCount[HttpOfferTypeProxyNameUri] > 0))\r
545 {\r
fa848a40
FS
546 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
547 Private->SelectProxyType = HttpOfferTypeProxyNameUri;\r
d1050b9d
MK
548 } else if ((Private->OfferCount[HttpOfferTypeDhcpDns] > 0) &&\r
549 (Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0))\r
550 {\r
fa848a40
FS
551 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
552 Private->SelectProxyType = HttpOfferTypeDhcpNameUri;\r
553 }\r
d933e70a
JW
554 }\r
555}\r
556\r
d933e70a
JW
557/**\r
558 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
559 to intercept events that occurred in the configuration process.\r
560\r
561 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
562 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
563 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
564 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
565 state transition.\r
566 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
567 @param[out] NewPacket The packet that is used to replace the above Packet.\r
568\r
569 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
570 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
571 driver will continue to wait for more DHCPOFFER packets until the\r
572 retry timeout expires.\r
573 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
574 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
575\r
576**/\r
577EFI_STATUS\r
578EFIAPI\r
579HttpBootDhcp4CallBack (\r
d1050b9d
MK
580 IN EFI_DHCP4_PROTOCOL *This,\r
581 IN VOID *Context,\r
582 IN EFI_DHCP4_STATE CurrentState,\r
583 IN EFI_DHCP4_EVENT Dhcp4Event,\r
584 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
585 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
d933e70a
JW
586 )\r
587{\r
d1050b9d
MK
588 HTTP_BOOT_PRIVATE_DATA *Private;\r
589 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
590 UINT16 Value;\r
591 EFI_STATUS Status;\r
592 BOOLEAN Received;\r
d933e70a 593\r
f75a7f56
LG
594 if ((Dhcp4Event != Dhcp4SendDiscover) &&\r
595 (Dhcp4Event != Dhcp4RcvdOffer) &&\r
596 (Dhcp4Event != Dhcp4SendRequest) &&\r
597 (Dhcp4Event != Dhcp4RcvdAck) &&\r
d1050b9d
MK
598 (Dhcp4Event != Dhcp4SelectOffer))\r
599 {\r
d933e70a
JW
600 return EFI_SUCCESS;\r
601 }\r
f75a7f56 602\r
d1050b9d 603 Private = (HTTP_BOOT_PRIVATE_DATA *)Context;\r
d933e70a
JW
604\r
605 //\r
606 // Override the Maximum DHCP Message Size.\r
607 //\r
608 MaxMsgSize = HttpBootParseDhcp4Options (\r
609 Packet->Dhcp4.Option,\r
610 GET_OPTION_BUFFER_LEN (Packet),\r
142c00c3 611 DHCP4_TAG_MAXMSG\r
d933e70a
JW
612 );\r
613 if (MaxMsgSize != NULL) {\r
614 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);\r
615 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
616 }\r
f75a7f56 617\r
95b5c32f
FS
618 //\r
619 // Callback to user if any packets sent or received.\r
620 //\r
d1050b9d
MK
621 if ((Private->HttpBootCallback != NULL) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
622 Received = (BOOLEAN)(Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);\r
623 Status = Private->HttpBootCallback->Callback (\r
624 Private->HttpBootCallback,\r
625 HttpBootDhcp4,\r
626 Received,\r
627 Packet->Length,\r
628 &Packet->Dhcp4\r
629 );\r
95b5c32f
FS
630 if (EFI_ERROR (Status)) {\r
631 return EFI_ABORTED;\r
632 }\r
633 }\r
d933e70a
JW
634\r
635 Status = EFI_SUCCESS;\r
636 switch (Dhcp4Event) {\r
d1050b9d
MK
637 case Dhcp4RcvdOffer:\r
638 Status = EFI_NOT_READY;\r
639 if (Packet->Length > HTTP_BOOT_DHCP4_PACKET_MAX_SIZE) {\r
640 //\r
641 // Ignore the incoming packets which exceed the maximum length.\r
642 //\r
643 break;\r
644 }\r
645\r
646 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
647 //\r
648 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
649 // the OfferIndex and OfferCount.\r
650 // If error happens, just ignore this packet and continue to wait more offer.\r
651 //\r
652 HttpBootCacheDhcp4Offer (Private, Packet);\r
653 }\r
654\r
a35dc649 655 break;\r
d1050b9d
MK
656\r
657 case Dhcp4SelectOffer:\r
d933e70a 658 //\r
d1050b9d
MK
659 // Select offer according to the priority in UEFI spec, and record the SelectIndex\r
660 // and SelectProxyType.\r
d933e70a 661 //\r
d1050b9d 662 HttpBootSelectDhcpOffer (Private);\r
d933e70a 663\r
d1050b9d
MK
664 if (Private->SelectIndex == 0) {\r
665 Status = EFI_ABORTED;\r
666 } else {\r
667 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
668 }\r
d933e70a 669\r
d1050b9d 670 break;\r
f75a7f56 671\r
d1050b9d
MK
672 default:\r
673 break;\r
d933e70a
JW
674 }\r
675\r
676 return Status;\r
677}\r
678\r
679/**\r
680 This function will register the IPv4 gateway address to the network device.\r
f75a7f56 681\r
d933e70a
JW
682 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
683\r
684 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
685 @retval Others Failed to configure the address.\r
686\r
687**/\r
688EFI_STATUS\r
689HttpBootRegisterIp4Gateway (\r
d1050b9d 690 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
691 )\r
692{\r
d1050b9d
MK
693 EFI_STATUS Status;\r
694 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
d933e70a
JW
695\r
696 ASSERT (!Private->UsingIpv6);\r
697\r
698 Ip4Config2 = Private->Ip4Config2;\r
699\r
700 //\r
701 // Configure the gateway if valid.\r
702 //\r
703 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {\r
704 Status = Ip4Config2->SetData (\r
705 Ip4Config2,\r
706 Ip4Config2DataTypeGateway,\r
707 sizeof (EFI_IPv4_ADDRESS),\r
708 &Private->GatewayIp\r
709 );\r
710 if (EFI_ERROR (Status)) {\r
711 return Status;\r
712 }\r
713 }\r
714\r
715 return EFI_SUCCESS;\r
716}\r
717\r
718/**\r
719 This function will register the default DNS addresses to the network device.\r
f75a7f56 720\r
d933e70a
JW
721 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
722 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
723 @param[in] DnsServerData Point a list of DNS server address in an array\r
724 of EFI_IPv4_ADDRESS instances.\r
725\r
726 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
727 @retval Others Failed to configure the address.\r
728\r
729**/\r
730EFI_STATUS\r
731HttpBootRegisterIp4Dns (\r
d1050b9d
MK
732 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
733 IN UINTN DataLength,\r
734 IN VOID *DnsServerData\r
d933e70a
JW
735 )\r
736{\r
d1050b9d 737 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
f75a7f56 738\r
d933e70a
JW
739 ASSERT (!Private->UsingIpv6);\r
740\r
741 Ip4Config2 = Private->Ip4Config2;\r
f75a7f56 742\r
d933e70a
JW
743 return Ip4Config2->SetData (\r
744 Ip4Config2,\r
745 Ip4Config2DataTypeDnsServer,\r
746 DataLength,\r
747 DnsServerData\r
748 );\r
749}\r
750\r
d933e70a
JW
751/**\r
752 This function will switch the IP4 configuration policy to Static.\r
753\r
754 @param[in] Private Pointer to HTTP boot driver private data.\r
755\r
756 @retval EFI_SUCCESS The policy is already configured to static.\r
757 @retval Others Other error as indicated..\r
758\r
759**/\r
760EFI_STATUS\r
b659408b 761HttpBootSetIp4Policy (\r
d1050b9d 762 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
763 )\r
764{\r
d1050b9d
MK
765 EFI_IP4_CONFIG2_POLICY Policy;\r
766 EFI_STATUS Status;\r
767 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
768 UINTN DataSize;\r
d933e70a
JW
769\r
770 Ip4Config2 = Private->Ip4Config2;\r
771\r
772 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
d1050b9d
MK
773 Status = Ip4Config2->GetData (\r
774 Ip4Config2,\r
775 Ip4Config2DataTypePolicy,\r
776 &DataSize,\r
777 &Policy\r
778 );\r
d933e70a
JW
779 if (EFI_ERROR (Status)) {\r
780 return Status;\r
781 }\r
782\r
783 if (Policy != Ip4Config2PolicyStatic) {\r
784 Policy = Ip4Config2PolicyStatic;\r
d1050b9d
MK
785 Status = Ip4Config2->SetData (\r
786 Ip4Config2,\r
787 Ip4Config2DataTypePolicy,\r
788 sizeof (EFI_IP4_CONFIG2_POLICY),\r
789 &Policy\r
790 );\r
d933e70a
JW
791 if (EFI_ERROR (Status)) {\r
792 return Status;\r
f75a7f56 793 }\r
d933e70a
JW
794 }\r
795\r
796 return EFI_SUCCESS;\r
797}\r
798\r
799/**\r
800 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
801\r
802 @param[in] Private Pointer to HTTP boot driver private data.\r
803\r
804 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
805 @retval Others Failed to finish the D.O.R.A process.\r
806\r
807**/\r
808EFI_STATUS\r
809HttpBootDhcp4Dora (\r
d1050b9d 810 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
811 )\r
812{\r
d1050b9d
MK
813 EFI_DHCP4_PROTOCOL *Dhcp4;\r
814 UINT32 OptCount;\r
815 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];\r
816 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];\r
817 EFI_DHCP4_CONFIG_DATA Config;\r
818 EFI_STATUS Status;\r
819 EFI_DHCP4_MODE_DATA Mode;\r
f75a7f56 820\r
d933e70a
JW
821 Dhcp4 = Private->Dhcp4;\r
822 ASSERT (Dhcp4 != NULL);\r
823\r
b659408b 824 Status = HttpBootSetIp4Policy (Private);\r
d933e70a
JW
825 if (EFI_ERROR (Status)) {\r
826 return Status;\r
827 }\r
828\r
829 //\r
830 // Build option list for the request packet.\r
831 //\r
832 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);\r
833 ASSERT (OptCount > 0);\r
834\r
d1050b9d 835 ZeroMem (&Config, sizeof (Config));\r
d933e70a
JW
836 Config.OptionCount = OptCount;\r
837 Config.OptionList = OptList;\r
838 Config.Dhcp4Callback = HttpBootDhcp4CallBack;\r
839 Config.CallbackContext = Private;\r
840 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;\r
841 Config.DiscoverTimeout = mHttpDhcpTimeout;\r
842\r
843 //\r
844 // Configure the DHCPv4 instance for HTTP boot.\r
845 //\r
846 Status = Dhcp4->Configure (Dhcp4, &Config);\r
847 if (EFI_ERROR (Status)) {\r
848 goto ON_EXIT;\r
849 }\r
850\r
851 //\r
852 // Initialize the record fields for DHCPv4 offer in private data.\r
853 //\r
854 Private->OfferNum = 0;\r
855 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
856 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
857\r
858 //\r
859 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.\r
860 //\r
861 Status = Dhcp4->Start (Dhcp4, NULL);\r
862 if (EFI_ERROR (Status)) {\r
863 goto ON_EXIT;\r
864 }\r
865\r
866 //\r
867 // Get the acquired IPv4 address and store them.\r
868 //\r
869 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
870 if (EFI_ERROR (Status)) {\r
871 goto ON_EXIT;\r
872 }\r
873\r
874 ASSERT (Mode.State == Dhcp4Bound);\r
875 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
876 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
877 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
878\r
879 Status = HttpBootRegisterIp4Gateway (Private);\r
880 if (EFI_ERROR (Status)) {\r
881 goto ON_EXIT;\r
882 }\r
883\r
884 AsciiPrint ("\n Station IP address is ");\r
885 HttpBootShowIp4Addr (&Private->StationIp.v4);\r
886 AsciiPrint ("\n");\r
887\r
888ON_EXIT:\r
889 if (EFI_ERROR (Status)) {\r
890 Dhcp4->Stop (Dhcp4);\r
891 Dhcp4->Configure (Dhcp4, NULL);\r
892 } else {\r
893 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
894 Dhcp4->Configure (Dhcp4, &Config);\r
895 }\r
896\r
897 return Status;\r
898}\r