]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
IntelFrameworkModulePkg: Refine casting expression result to bigger size
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDhcp4.c
... / ...
CommitLineData
1/** @file\r
2 Functions implementation related with DHCPv4 for HTTP boot driver.\r
3\r
4Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
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 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
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 = 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] = 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
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 = 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 = 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 = 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 = DHCP4_TAG_VENDOR_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 != 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 == 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 @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
226**/\r
227EFI_STATUS\r
228HttpBootCacheDhcp4Packet (\r
229 IN EFI_DHCP4_PACKET *Dst,\r
230 IN EFI_DHCP4_PACKET *Src\r
231 )\r
232{\r
233 if (Dst->Size < Src->Length) {\r
234 return EFI_BUFFER_TOO_SMALL;\r
235 }\r
236\r
237 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
238 Dst->Length = Src->Length;\r
239\r
240 return EFI_SUCCESS;\r
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
269 BOOLEAN FileFieldOverloaded;\r
270 \r
271 IsDnsOffer = FALSE;\r
272 IpExpressedUri = FALSE;\r
273 IsProxyOffer = FALSE;\r
274 IsHttpOffer = FALSE;\r
275 FileFieldOverloaded = FALSE;\r
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
300 FileFieldOverloaded = TRUE;\r
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
332 // The offer with "HTTPClient" is a Http offer.\r
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
364 } else if (!FileFieldOverloaded && Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
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
408 if (IsProxyOffer) {\r
409 OfferType = HttpOfferTypeProxyIpUri;\r
410 } else {\r
411 OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;\r
412 }\r
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
439 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
440 @retval Others Operation failed.\r
441**/\r
442EFI_STATUS\r
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
451 EFI_STATUS Status;\r
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
460 Status = HttpBootCacheDhcp4Packet (Offer, RcvdOffer);\r
461 if (EFI_ERROR (Status)) {\r
462 return Status;\r
463 }\r
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
469 return EFI_ABORTED;\r
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
481\r
482 return EFI_SUCCESS;\r
483}\r
484\r
485/**\r
486 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
487\r
488 @param[in] Private Pointer to HTTP boot driver private data.\r
489\r
490**/\r
491VOID\r
492HttpBootSelectDhcpOffer (\r
493 IN HTTP_BOOT_PRIVATE_DATA *Private\r
494 )\r
495{\r
496 Private->SelectIndex = 0;\r
497 Private->SelectProxyType = HttpOfferTypeMax;\r
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
510 \r
511 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
512 \r
513 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
514 \r
515 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
516 \r
517 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) {\r
518 \r
519 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
520 \r
521 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
522 \r
523 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
524 }\r
525 \r
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
546 \r
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
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
625 DHCP4_TAG_MAXMSG\r
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
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
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
646 // If error happens, just ignore this packet and continue to wait more offer.\r
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
657 HttpBootSelectDhcpOffer (Private);\r
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
756HttpBootSetIp4Policy (\r
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
819 Status = HttpBootSetIp4Policy (Private);\r
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