]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
NetworkPkg/HttpBootDxe: fix typo in DHCPv4 packet parsing
[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 - 2017, 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 >= 10) &&\r
336 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 10) == 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 if (Cache4->UriParser != NULL) {\r
426 FreePool (Cache4->UriParser);\r
427 }\r
428 return EFI_DEVICE_ERROR;\r
429 }\r
430 }\r
431 \r
432 Cache4->OfferType = OfferType;\r
433 return EFI_SUCCESS;\r
434}\r
435\r
436/**\r
437 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
438\r
439 @param[in] Private Pointer to HTTP boot driver private data.\r
440 @param[in] RcvdOffer Pointer to the received offer packet.\r
441\r
442 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
443 @retval Others Operation failed.\r
444**/\r
445EFI_STATUS\r
446HttpBootCacheDhcp4Offer (\r
447 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
448 IN EFI_DHCP4_PACKET *RcvdOffer\r
449 )\r
450{\r
451 HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4;\r
452 EFI_DHCP4_PACKET *Offer;\r
453 HTTP_BOOT_OFFER_TYPE OfferType;\r
454 EFI_STATUS Status;\r
455\r
456 ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM);\r
457 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
458 Offer = &Cache4->Packet.Offer;\r
459\r
460 //\r
461 // Cache the content of DHCPv4 packet firstly.\r
462 //\r
463 Status = HttpBootCacheDhcp4Packet (Offer, RcvdOffer);\r
464 if (EFI_ERROR (Status)) {\r
465 return Status;\r
466 }\r
467\r
468 //\r
469 // Validate the DHCPv4 packet, and parse the options and offer type.\r
470 //\r
471 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) {\r
472 return EFI_ABORTED;\r
473 }\r
474\r
475 //\r
476 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
477 //\r
478 OfferType = Cache4->OfferType;\r
479 ASSERT (OfferType < HttpOfferTypeMax);\r
480 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
481 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
482 Private->OfferCount[OfferType]++;\r
483 Private->OfferNum++;\r
484\r
485 return EFI_SUCCESS;\r
486}\r
487\r
488/**\r
489 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.\r
490\r
491 @param[in] Private Pointer to HTTP boot driver private data.\r
492\r
493**/\r
494VOID\r
495HttpBootSelectDhcpOffer (\r
496 IN HTTP_BOOT_PRIVATE_DATA *Private\r
497 )\r
498{\r
499 Private->SelectIndex = 0;\r
500 Private->SelectProxyType = HttpOfferTypeMax;\r
501\r
502 if (Private->FilePathUri != NULL) {\r
503 //\r
504 // We are in home environment, the URI is already specified.\r
505 // Just need to choose a DHCP offer.\r
506 // The offer with DNS server address takes priority here.\r
507 //\r
508 if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0) {\r
509 \r
510 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
511 \r
512 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
513 \r
514 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
515 \r
516 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
517 \r
518 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
519 \r
520 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0) {\r
521 \r
522 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
523 \r
524 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
525 \r
526 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
527 }\r
528 \r
529 } else {\r
530 //\r
531 // We are in corporate environment.\r
532 //\r
533 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns\r
534 // Priority2: HttpOfferTypeDhcpNameUriDns \r
535 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri \r
536 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri \r
537 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri\r
538 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri \r
539 // \r
540 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
541 \r
542 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
543 \r
544 } else if (Private->OfferCount[HttpOfferTypeDhcpIpUriDns] > 0) {\r
545 \r
546 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUriDns][0] + 1;\r
547 \r
548 }else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
549 \r
550 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
551 \r
552 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 &&\r
553 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
554 \r
555 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
556 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
557 \r
558 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
559 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
560 \r
561 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
562 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
563 \r
564 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
565 Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) {\r
566 \r
567 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
568 Private->SelectProxyType = HttpOfferTypeProxyNameUri;\r
569 \r
570 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
571 Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) {\r
572 \r
573 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
574 Private->SelectProxyType = HttpOfferTypeDhcpNameUri;\r
575 }\r
576 }\r
577}\r
578\r
579\r
580/**\r
581 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
582 to intercept events that occurred in the configuration process.\r
583\r
584 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
585 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
586 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
587 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
588 state transition.\r
589 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
590 @param[out] NewPacket The packet that is used to replace the above Packet.\r
591\r
592 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
593 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
594 driver will continue to wait for more DHCPOFFER packets until the\r
595 retry timeout expires.\r
596 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
597 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
598\r
599**/\r
600EFI_STATUS\r
601EFIAPI\r
602HttpBootDhcp4CallBack (\r
603 IN EFI_DHCP4_PROTOCOL *This,\r
604 IN VOID *Context,\r
605 IN EFI_DHCP4_STATE CurrentState,\r
606 IN EFI_DHCP4_EVENT Dhcp4Event,\r
607 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
608 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
609 )\r
610{\r
611 HTTP_BOOT_PRIVATE_DATA *Private;\r
612 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
613 UINT16 Value;\r
614 EFI_STATUS Status;\r
615 BOOLEAN Received;\r
616\r
617 if ((Dhcp4Event != Dhcp4SendDiscover) && \r
618 (Dhcp4Event != Dhcp4RcvdOffer) && \r
619 (Dhcp4Event != Dhcp4SendRequest) && \r
620 (Dhcp4Event != Dhcp4RcvdAck) && \r
621 (Dhcp4Event != Dhcp4SelectOffer)) {\r
622 return EFI_SUCCESS;\r
623 }\r
624 \r
625 Private = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
626\r
627 //\r
628 // Override the Maximum DHCP Message Size.\r
629 //\r
630 MaxMsgSize = HttpBootParseDhcp4Options (\r
631 Packet->Dhcp4.Option,\r
632 GET_OPTION_BUFFER_LEN (Packet),\r
633 DHCP4_TAG_MAXMSG\r
634 );\r
635 if (MaxMsgSize != NULL) {\r
636 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);\r
637 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
638 }\r
639 \r
640 //\r
641 // Callback to user if any packets sent or received.\r
642 //\r
643 if (Private->HttpBootCallback != NULL && Dhcp4Event != Dhcp4SelectOffer) {\r
644 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);\r
645 Status = Private->HttpBootCallback->Callback (\r
646 Private->HttpBootCallback, \r
647 HttpBootDhcp4,\r
648 Received,\r
649 Packet->Length,\r
650 &Packet->Dhcp4\r
651 );\r
652 if (EFI_ERROR (Status)) {\r
653 return EFI_ABORTED;\r
654 }\r
655 }\r
656\r
657 Status = EFI_SUCCESS;\r
658 switch (Dhcp4Event) {\r
659 case Dhcp4RcvdOffer:\r
660 Status = EFI_NOT_READY;\r
661 if (Packet->Length > HTTP_BOOT_DHCP4_PACKET_MAX_SIZE) {\r
662 //\r
663 // Ignore the incoming packets which exceed the maximum length.\r
664 //\r
665 break;\r
666 }\r
667 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
668 //\r
669 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
670 // the OfferIndex and OfferCount.\r
671 // If error happens, just ignore this packet and continue to wait more offer.\r
672 //\r
673 HttpBootCacheDhcp4Offer (Private, Packet);\r
674 }\r
675 break;\r
676\r
677 case Dhcp4SelectOffer:\r
678 //\r
679 // Select offer according to the priority in UEFI spec, and record the SelectIndex \r
680 // and SelectProxyType.\r
681 //\r
682 HttpBootSelectDhcpOffer (Private);\r
683\r
684 if (Private->SelectIndex == 0) {\r
685 Status = EFI_ABORTED;\r
686 } else {\r
687 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
688 }\r
689 break;\r
690 \r
691 default:\r
692 break;\r
693 }\r
694\r
695 return Status;\r
696}\r
697\r
698/**\r
699 This function will register the IPv4 gateway address to the network device.\r
700 \r
701 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
702\r
703 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
704 @retval Others Failed to configure the address.\r
705\r
706**/\r
707EFI_STATUS\r
708HttpBootRegisterIp4Gateway (\r
709 IN HTTP_BOOT_PRIVATE_DATA *Private\r
710 )\r
711{\r
712 EFI_STATUS Status;\r
713 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
714\r
715 ASSERT (!Private->UsingIpv6);\r
716\r
717 Ip4Config2 = Private->Ip4Config2;\r
718\r
719 //\r
720 // Configure the gateway if valid.\r
721 //\r
722 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {\r
723 Status = Ip4Config2->SetData (\r
724 Ip4Config2,\r
725 Ip4Config2DataTypeGateway,\r
726 sizeof (EFI_IPv4_ADDRESS),\r
727 &Private->GatewayIp\r
728 );\r
729 if (EFI_ERROR (Status)) {\r
730 return Status;\r
731 }\r
732 }\r
733\r
734 return EFI_SUCCESS;\r
735}\r
736\r
737/**\r
738 This function will register the default DNS addresses to the network device.\r
739 \r
740 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
741 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
742 @param[in] DnsServerData Point a list of DNS server address in an array\r
743 of EFI_IPv4_ADDRESS instances.\r
744\r
745 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
746 @retval Others Failed to configure the address.\r
747\r
748**/\r
749EFI_STATUS\r
750HttpBootRegisterIp4Dns (\r
751 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
752 IN UINTN DataLength,\r
753 IN VOID *DnsServerData\r
754 )\r
755{\r
756 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
757 \r
758 ASSERT (!Private->UsingIpv6);\r
759\r
760 Ip4Config2 = Private->Ip4Config2;\r
761 \r
762 return Ip4Config2->SetData (\r
763 Ip4Config2,\r
764 Ip4Config2DataTypeDnsServer,\r
765 DataLength,\r
766 DnsServerData\r
767 );\r
768}\r
769\r
770\r
771/**\r
772 This function will switch the IP4 configuration policy to Static.\r
773\r
774 @param[in] Private Pointer to HTTP boot driver private data.\r
775\r
776 @retval EFI_SUCCESS The policy is already configured to static.\r
777 @retval Others Other error as indicated..\r
778\r
779**/\r
780EFI_STATUS\r
781HttpBootSetIp4Policy (\r
782 IN HTTP_BOOT_PRIVATE_DATA *Private\r
783 )\r
784{\r
785 EFI_IP4_CONFIG2_POLICY Policy;\r
786 EFI_STATUS Status;\r
787 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
788 UINTN DataSize;\r
789\r
790 Ip4Config2 = Private->Ip4Config2;\r
791\r
792 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
793 Status = Ip4Config2->GetData (\r
794 Ip4Config2,\r
795 Ip4Config2DataTypePolicy,\r
796 &DataSize,\r
797 &Policy\r
798 );\r
799 if (EFI_ERROR (Status)) {\r
800 return Status;\r
801 }\r
802\r
803 if (Policy != Ip4Config2PolicyStatic) {\r
804 Policy = Ip4Config2PolicyStatic;\r
805 Status= Ip4Config2->SetData (\r
806 Ip4Config2,\r
807 Ip4Config2DataTypePolicy,\r
808 sizeof (EFI_IP4_CONFIG2_POLICY),\r
809 &Policy\r
810 );\r
811 if (EFI_ERROR (Status)) {\r
812 return Status;\r
813 } \r
814 }\r
815\r
816 return EFI_SUCCESS;\r
817}\r
818\r
819/**\r
820 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
821\r
822 @param[in] Private Pointer to HTTP boot driver private data.\r
823\r
824 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
825 @retval Others Failed to finish the D.O.R.A process.\r
826\r
827**/\r
828EFI_STATUS\r
829HttpBootDhcp4Dora (\r
830 IN HTTP_BOOT_PRIVATE_DATA *Private\r
831 )\r
832{\r
833 EFI_DHCP4_PROTOCOL *Dhcp4;\r
834 UINT32 OptCount;\r
835 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];\r
836 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];\r
837 EFI_DHCP4_CONFIG_DATA Config;\r
838 EFI_STATUS Status;\r
839 EFI_DHCP4_MODE_DATA Mode;\r
840 \r
841 Dhcp4 = Private->Dhcp4;\r
842 ASSERT (Dhcp4 != NULL);\r
843\r
844 Status = HttpBootSetIp4Policy (Private);\r
845 if (EFI_ERROR (Status)) {\r
846 return Status;\r
847 }\r
848\r
849 //\r
850 // Build option list for the request packet.\r
851 //\r
852 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);\r
853 ASSERT (OptCount > 0);\r
854\r
855 ZeroMem (&Config, sizeof(Config));\r
856 Config.OptionCount = OptCount;\r
857 Config.OptionList = OptList;\r
858 Config.Dhcp4Callback = HttpBootDhcp4CallBack;\r
859 Config.CallbackContext = Private;\r
860 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;\r
861 Config.DiscoverTimeout = mHttpDhcpTimeout;\r
862\r
863 //\r
864 // Configure the DHCPv4 instance for HTTP boot.\r
865 //\r
866 Status = Dhcp4->Configure (Dhcp4, &Config);\r
867 if (EFI_ERROR (Status)) {\r
868 goto ON_EXIT;\r
869 }\r
870\r
871 //\r
872 // Initialize the record fields for DHCPv4 offer in private data.\r
873 //\r
874 Private->OfferNum = 0;\r
875 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
876 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
877\r
878 //\r
879 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.\r
880 //\r
881 Status = Dhcp4->Start (Dhcp4, NULL);\r
882 if (EFI_ERROR (Status)) {\r
883 goto ON_EXIT;\r
884 }\r
885\r
886 //\r
887 // Get the acquired IPv4 address and store them.\r
888 //\r
889 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
890 if (EFI_ERROR (Status)) {\r
891 goto ON_EXIT;\r
892 }\r
893\r
894 ASSERT (Mode.State == Dhcp4Bound);\r
895 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
896 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
897 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
898\r
899 Status = HttpBootRegisterIp4Gateway (Private);\r
900 if (EFI_ERROR (Status)) {\r
901 goto ON_EXIT;\r
902 }\r
903\r
904 AsciiPrint ("\n Station IP address is ");\r
905 HttpBootShowIp4Addr (&Private->StationIp.v4);\r
906 AsciiPrint ("\n");\r
907\r
908ON_EXIT:\r
909 if (EFI_ERROR (Status)) {\r
910 Dhcp4->Stop (Dhcp4);\r
911 Dhcp4->Configure (Dhcp4, NULL);\r
912 } else {\r
913 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
914 Dhcp4->Configure (Dhcp4, &Config);\r
915 }\r
916\r
917 return Status;\r
918}\r