]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDhcp4.c
ShellPkg: Don't strip positional parameters of quotation marks.
[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
4Copyright (c) 2015, 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 HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN,\r
22 HTTP_BOOT_DHCP4_TAG_OVERLOAD,\r
23 HTTP_BOOT_DHCP4_TAG_MSG_TYPE,\r
24 HTTP_BOOT_DHCP4_TAG_SERVER_ID,\r
25 HTTP_BOOT_DHCP4_TAG_CLASS_ID,\r
26 HTTP_BOOT_DHCP4_TAG_BOOTFILE,\r
27 HTTP_BOOT_DHCP4_TAG_DNS_SERVER\r
28};\r
29\r
30//\r
31// There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec.\r
32//\r
33UINT32 mHttpDhcpTimeout[4] = {4, 8, 16, 32};\r
34\r
35/**\r
36 Build the options buffer for the DHCPv4 request packet.\r
37\r
38 @param[in] Private Pointer to HTTP boot driver private data.\r
39 @param[out] OptList Pointer to the option pointer array.\r
40 @param[in] Buffer Pointer to the buffer to contain the option list.\r
41\r
42 @return Index The count of the built-in options.\r
43\r
44**/\r
45UINT32\r
46HttpBootBuildDhcp4Options (\r
47 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
48 OUT EFI_DHCP4_PACKET_OPTION **OptList,\r
49 IN UINT8 *Buffer\r
50 )\r
51{\r
52 HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt;\r
53 UINT16 Value;\r
54 UINT32 Index;\r
55\r
56 Index = 0;\r
57 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
58\r
59 //\r
60 // Append parameter request list option.\r
61 //\r
62 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_PARA_LIST;\r
63 OptList[Index]->Length = 27;\r
64 OptEnt.Para = (HTTP_BOOT_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
65 OptEnt.Para->ParaList[0] = HTTP_BOOT_DHCP4_TAG_NETMASK;\r
66 OptEnt.Para->ParaList[1] = HTTP_BOOT_DHCP4_TAG_TIME_OFFSET;\r
67 OptEnt.Para->ParaList[2] = HTTP_BOOT_DHCP4_TAG_ROUTER;\r
68 OptEnt.Para->ParaList[3] = HTTP_BOOT_DHCP4_TAG_TIME_SERVER;\r
69 OptEnt.Para->ParaList[4] = HTTP_BOOT_DHCP4_TAG_NAME_SERVER;\r
70 OptEnt.Para->ParaList[5] = HTTP_BOOT_DHCP4_TAG_DNS_SERVER;\r
71 OptEnt.Para->ParaList[6] = HTTP_BOOT_DHCP4_TAG_HOSTNAME;\r
72 OptEnt.Para->ParaList[7] = HTTP_BOOT_DHCP4_TAG_BOOTFILE_LEN;\r
73 OptEnt.Para->ParaList[8] = HTTP_BOOT_DHCP4_TAG_DOMAINNAME;\r
74 OptEnt.Para->ParaList[9] = HTTP_BOOT_DHCP4_TAG_ROOTPATH;\r
75 OptEnt.Para->ParaList[10] = HTTP_BOOT_DHCP4_TAG_EXTEND_PATH;\r
76 OptEnt.Para->ParaList[11] = HTTP_BOOT_DHCP4_TAG_EMTU;\r
77 OptEnt.Para->ParaList[12] = HTTP_BOOT_DHCP4_TAG_TTL;\r
78 OptEnt.Para->ParaList[13] = HTTP_BOOT_DHCP4_TAG_BROADCAST;\r
79 OptEnt.Para->ParaList[14] = HTTP_BOOT_DHCP4_TAG_NIS_DOMAIN;\r
80 OptEnt.Para->ParaList[15] = HTTP_BOOT_DHCP4_TAG_NIS_SERVER;\r
81 OptEnt.Para->ParaList[16] = HTTP_BOOT_DHCP4_TAG_NTP_SERVER;\r
82 OptEnt.Para->ParaList[17] = HTTP_BOOT_DHCP4_TAG_VENDOR;\r
83 OptEnt.Para->ParaList[18] = HTTP_BOOT_DHCP4_TAG_REQUEST_IP;\r
84 OptEnt.Para->ParaList[19] = HTTP_BOOT_DHCP4_TAG_LEASE;\r
85 OptEnt.Para->ParaList[20] = HTTP_BOOT_DHCP4_TAG_SERVER_ID;\r
86 OptEnt.Para->ParaList[21] = HTTP_BOOT_DHCP4_TAG_T1;\r
87 OptEnt.Para->ParaList[22] = HTTP_BOOT_DHCP4_TAG_T2;\r
88 OptEnt.Para->ParaList[23] = HTTP_BOOT_DHCP4_TAG_CLASS_ID;\r
89 OptEnt.Para->ParaList[25] = HTTP_BOOT_DHCP4_TAG_BOOTFILE;\r
90 OptEnt.Para->ParaList[26] = HTTP_BOOT_DHCP4_TAG_UUID;\r
91 Index++;\r
92 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
93\r
94 //\r
95 // Append UUID/Guid-based client identifier option\r
96 //\r
97 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UUID;\r
98 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UUID);\r
99 OptEnt.Uuid = (HTTP_BOOT_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
100 OptEnt.Uuid->Type = 0;\r
101 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {\r
102 //\r
103 // Zero the Guid to indicate NOT programable if failed to get system Guid.\r
104 //\r
105 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
106 }\r
107 Index++;\r
108 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
109\r
110 //\r
111 // Append client network device interface option\r
112 //\r
113 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_UNDI;\r
114 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI);\r
115 OptEnt.Undi = (HTTP_BOOT_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
116\r
117 if (Private->Nii != NULL) {\r
118 OptEnt.Undi->Type = Private->Nii->Type;\r
119 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
120 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
121 } else {\r
122 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
123 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
124 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
125 }\r
126\r
127 Index++;\r
128 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
129\r
130 //\r
131 // Append client system architecture option\r
132 //\r
133 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_ARCH;\r
134 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH);\r
135 OptEnt.Arch = (HTTP_BOOT_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
136 Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);\r
137 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
138 Index++;\r
139 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
140\r
141 //\r
142 // Append vendor class identify option\r
143 //\r
144 OptList[Index]->OpCode = HTTP_BOOT_DHCP4_TAG_CLASS_ID;\r
145 OptList[Index]->Length = (UINT8) sizeof (HTTP_BOOT_DHCP4_OPTION_CLID);\r
146 OptEnt.Clid = (HTTP_BOOT_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
147 CopyMem (\r
148 OptEnt.Clid,\r
149 DEFAULT_CLASS_ID_DATA,\r
150 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID)\r
151 );\r
152 HttpBootUintnToAscDecWithFormat (\r
153 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,\r
154 OptEnt.Clid->ArchitectureType,\r
155 sizeof (OptEnt.Clid->ArchitectureType)\r
156 );\r
157\r
158 if (Private->Nii != NULL) {\r
159 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
160 HttpBootUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
161 HttpBootUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
162 }\r
163\r
164 Index++;\r
165\r
166 return Index;\r
167}\r
168\r
169/**\r
170 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.\r
171\r
172 @param[in] Buffer Pointer to the option buffer.\r
173 @param[in] Length Length of the option buffer.\r
174 @param[in] OptTag Tag of the required option.\r
175\r
176 @retval NULL Failed to find the required option.\r
177 @retval Others The position of the required option.\r
178\r
179**/\r
180EFI_DHCP4_PACKET_OPTION *\r
181HttpBootParseDhcp4Options (\r
182 IN UINT8 *Buffer,\r
183 IN UINT32 Length,\r
184 IN UINT8 OptTag\r
185 )\r
186{\r
187 EFI_DHCP4_PACKET_OPTION *Option;\r
188 UINT32 Offset;\r
189\r
190 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
191 Offset = 0;\r
192\r
193 while (Offset < Length && Option->OpCode != HTTP_BOOT_DHCP4_TAG_EOP) {\r
194\r
195 if (Option->OpCode == OptTag) {\r
196 //\r
197 // Found the required option.\r
198 //\r
199 return Option;\r
200 }\r
201\r
202 //\r
203 // Skip the current option to the next.\r
204 //\r
205 if (Option->OpCode == HTTP_BOOT_DHCP4_TAG_PAD) {\r
206 Offset++;\r
207 } else {\r
208 Offset += Option->Length + 2;\r
209 }\r
210\r
211 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
212 }\r
213\r
214 return NULL;\r
215}\r
216\r
217/**\r
218 Cache the DHCPv4 packet.\r
219\r
220 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.\r
221 @param[in] Src Pointer to the DHCPv4 packet to be cached.\r
222\r
223**/\r
224VOID\r
225HttpBootCacheDhcp4Packet (\r
226 IN EFI_DHCP4_PACKET *Dst,\r
227 IN EFI_DHCP4_PACKET *Src\r
228 )\r
229{\r
230 ASSERT (Dst->Size >= Src->Length);\r
231\r
232 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
233 Dst->Length = Src->Length;\r
234}\r
235\r
236/**\r
237 Parse the cached DHCPv4 packet, including all the options.\r
238\r
239 @param[in] Cache4 Pointer to cached DHCPv4 packet.\r
240\r
241 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.\r
242 @retval EFI_DEVICE_ERROR Failed to parse an invalid packet.\r
243\r
244**/\r
245EFI_STATUS\r
246HttpBootParseDhcp4Packet (\r
247 IN HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4\r
248 )\r
249{\r
250 EFI_DHCP4_PACKET *Offer;\r
251 EFI_DHCP4_PACKET_OPTION **Options;\r
252 UINTN Index;\r
253 EFI_DHCP4_PACKET_OPTION *Option;\r
254 BOOLEAN IsProxyOffer;\r
255 BOOLEAN IsHttpOffer;\r
256 BOOLEAN IsDnsOffer;\r
257 BOOLEAN IpExpressedUri;\r
258 UINT8 *Ptr8;\r
259 EFI_STATUS Status;\r
260 HTTP_BOOT_OFFER_TYPE OfferType;\r
261 EFI_IPv4_ADDRESS IpAddr;\r
262 \r
263 IsDnsOffer = FALSE;\r
264 IpExpressedUri = FALSE;\r
265 IsProxyOffer = FALSE;\r
266 IsHttpOffer = FALSE;\r
267\r
268 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));\r
269\r
270 Offer = &Cache4->Packet.Offer;\r
271 Options = Cache4->OptList;\r
272\r
273 //\r
274 // Parse DHCPv4 options in this offer, and store the pointers.\r
275 // First, try to parse DHCPv4 options from the DHCP optional parameters field.\r
276 //\r
277 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
278 Options[Index] = HttpBootParseDhcp4Options (\r
279 Offer->Dhcp4.Option,\r
280 GET_OPTION_BUFFER_LEN (Offer),\r
281 mInterestedDhcp4Tags[Index]\r
282 );\r
283 }\r
284 //\r
285 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132. \r
286 // If yes, try to parse options from the BootFileName field, then ServerName field.\r
287 //\r
288 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD];\r
289 if (Option != NULL) {\r
290 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE) != 0) {\r
291 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
292 if (Options[Index] == NULL) {\r
293 Options[Index] = HttpBootParseDhcp4Options (\r
294 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
295 sizeof (Offer->Dhcp4.Header.BootFileName),\r
296 mInterestedDhcp4Tags[Index]\r
297 );\r
298 }\r
299 }\r
300 }\r
301 if ((Option->Data[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME) != 0) {\r
302 for (Index = 0; Index < HTTP_BOOT_DHCP4_TAG_INDEX_MAX; Index++) {\r
303 if (Options[Index] == NULL) {\r
304 Options[Index] = HttpBootParseDhcp4Options (\r
305 (UINT8 *) Offer->Dhcp4.Header.ServerName,\r
306 sizeof (Offer->Dhcp4.Header.ServerName),\r
307 mInterestedDhcp4Tags[Index]\r
308 );\r
309 }\r
310 }\r
311 }\r
312 }\r
313\r
314 //\r
315 // The offer with "yiaddr" is a proxy offer.\r
316 //\r
317 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {\r
318 IsProxyOffer = TRUE;\r
319 }\r
320\r
321 //\r
322 // The offer with "HttpClient" is a Http offer.\r
323 //\r
324 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID];\r
325 if ((Option != NULL) && (Option->Length >= 9) &&\r
326 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
327 IsHttpOffer = TRUE;\r
328 }\r
329\r
330 //\r
331 // The offer with Domain Server is a DNS offer.\r
332 //\r
333 Option = Options[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER];\r
334 if (Option != NULL) {\r
335 IsDnsOffer = TRUE;\r
336 }\r
337\r
338 //\r
339 // Parse boot file name:\r
340 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.\r
341 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.\r
342 // Otherwise, read from boot file field in DHCP header.\r
343 //\r
344 if (Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
345 //\r
346 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null\r
347 // terminated string. So force to append null terminated character at the end of string.\r
348 //\r
349 Ptr8 = (UINT8*)&Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];\r
350 Ptr8 += Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Length;\r
351 if (*(Ptr8 - 1) != '\0') {\r
352 *Ptr8 = '\0';\r
353 }\r
354 } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {\r
355 //\r
356 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.\r
357 // Do not count dhcp option header here, or else will destroy the serverhostname.\r
358 //\r
359 Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)\r
360 (&Offer->Dhcp4.Header.BootFileName[0] -\r
361 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
362 }\r
363\r
364 //\r
365 // Http offer must have a boot URI.\r
366 //\r
367 if (IsHttpOffer && Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {\r
368 return EFI_DEVICE_ERROR;\r
369 }\r
370\r
371 //\r
372 // Try to retrieve the IP of HTTP server from URI. \r
373 //\r
374 if (IsHttpOffer) {\r
375 Status = HttpParseUrl (\r
376 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
377 (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data),\r
378 FALSE,\r
379 &Cache4->UriParser\r
380 );\r
381 if (EFI_ERROR (Status)) {\r
382 return EFI_DEVICE_ERROR;\r
383 }\r
384\r
385 Status = HttpUrlGetIp4 (\r
386 (CHAR8*) Options[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE]->Data,\r
387 Cache4->UriParser,\r
388 &IpAddr\r
389 );\r
390 IpExpressedUri = !EFI_ERROR (Status);\r
391 }\r
392\r
393 //\r
394 // Determine offer type of the DHCPv4 packet.\r
395 //\r
396 if (IsHttpOffer) {\r
397 if (IpExpressedUri) {\r
398 OfferType = IsProxyOffer ? HttpOfferTypeProxyIpUri : HttpOfferTypeDhcpIpUri;\r
399 } else {\r
400 if (!IsProxyOffer) {\r
401 OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;\r
402 } else {\r
403 OfferType = HttpOfferTypeProxyNameUri;\r
404 }\r
405 }\r
406\r
407 } else {\r
408 if (!IsProxyOffer) {\r
409 OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;\r
410 } else {\r
411 return EFI_DEVICE_ERROR;\r
412 }\r
413 }\r
414 \r
415 Cache4->OfferType = OfferType;\r
416 return EFI_SUCCESS;\r
417}\r
418\r
419/**\r
420 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.\r
421\r
422 @param[in] Private Pointer to HTTP boot driver private data.\r
423 @param[in] RcvdOffer Pointer to the received offer packet.\r
424\r
425**/\r
426VOID\r
427HttpBootCacheDhcp4Offer (\r
428 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
429 IN EFI_DHCP4_PACKET *RcvdOffer\r
430 )\r
431{\r
432 HTTP_BOOT_DHCP4_PACKET_CACHE *Cache4;\r
433 EFI_DHCP4_PACKET *Offer;\r
434 HTTP_BOOT_OFFER_TYPE OfferType;\r
435\r
436 ASSERT (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM);\r
437 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;\r
438 Offer = &Cache4->Packet.Offer;\r
439\r
440 //\r
441 // Cache the content of DHCPv4 packet firstly.\r
442 //\r
443 HttpBootCacheDhcp4Packet (Offer, RcvdOffer);\r
444\r
445 //\r
446 // Validate the DHCPv4 packet, and parse the options and offer type.\r
447 //\r
448 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4))) {\r
449 return;\r
450 }\r
451\r
452 //\r
453 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
454 //\r
455 OfferType = Cache4->OfferType;\r
456 ASSERT (OfferType < HttpOfferTypeMax);\r
457 ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);\r
458 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
459 Private->OfferCount[OfferType]++;\r
460 Private->OfferNum++;\r
461}\r
462\r
463/**\r
464 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.\r
465\r
466 @param[in] Private Pointer to HTTP boot driver private data.\r
467\r
468**/\r
469VOID\r
470HttpBootSelectDhcp4Offer (\r
471 IN HTTP_BOOT_PRIVATE_DATA *Private\r
472 )\r
473{\r
474 Private->SelectIndex = 0;\r
475 Private->SelectProxyType = HttpOfferTypeMax;\r
476 \r
477 //\r
478 // Priority1: HttpOfferTypeDhcpIpUri \r
479 // Priority2: HttpOfferTypeDhcpNameUriDns \r
480 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri \r
481 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri \r
482 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri\r
483 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri \r
484 // \r
485 if (Private->OfferCount[HttpOfferTypeDhcpIpUri] > 0) {\r
486 \r
487 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpIpUri][0] + 1;\r
488 \r
489 } else if (Private->OfferCount[HttpOfferTypeDhcpNameUriDns] > 0) {\r
490 \r
491 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpNameUriDns][0] + 1;\r
492 \r
493 } else if (Private->OfferCount[HttpOfferTypeDhcpOnly] > 0 &&\r
494 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
495 \r
496 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpOnly][0] + 1;\r
497 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
498 \r
499 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
500 Private->OfferCount[HttpOfferTypeProxyIpUri] > 0) {\r
501 \r
502 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
503 Private->SelectProxyType = HttpOfferTypeProxyIpUri;\r
504 \r
505 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
506 Private->OfferCount[HttpOfferTypeProxyNameUri] > 0) {\r
507 \r
508 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
509 Private->SelectProxyType = HttpOfferTypeProxyNameUri;\r
510 \r
511 } else if (Private->OfferCount[HttpOfferTypeDhcpDns] > 0 &&\r
512 Private->OfferCount[HttpOfferTypeDhcpNameUri] > 0) {\r
513 \r
514 Private->SelectIndex = Private->OfferIndex[HttpOfferTypeDhcpDns][0] + 1;\r
515 Private->SelectProxyType = HttpOfferTypeDhcpNameUri;\r
516 }\r
517}\r
518\r
519\r
520/**\r
521 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver\r
522 to intercept events that occurred in the configuration process.\r
523\r
524 @param[in] This Pointer to the EFI DHCPv4 Protocol.\r
525 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().\r
526 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.\r
527 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a\r
528 state transition.\r
529 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.\r
530 @param[out] NewPacket The packet that is used to replace the above Packet.\r
531\r
532 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.\r
533 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol\r
534 driver will continue to wait for more DHCPOFFER packets until the\r
535 retry timeout expires.\r
536 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process\r
537 and return to the Dhcp4Init or Dhcp4InitReboot state.\r
538\r
539**/\r
540EFI_STATUS\r
541EFIAPI\r
542HttpBootDhcp4CallBack (\r
543 IN EFI_DHCP4_PROTOCOL *This,\r
544 IN VOID *Context,\r
545 IN EFI_DHCP4_STATE CurrentState,\r
546 IN EFI_DHCP4_EVENT Dhcp4Event,\r
547 IN EFI_DHCP4_PACKET *Packet OPTIONAL,\r
548 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
549 )\r
550{\r
551 HTTP_BOOT_PRIVATE_DATA *Private;\r
552 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
553 UINT16 Value;\r
554 EFI_STATUS Status;\r
555\r
556 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
557 return EFI_SUCCESS;\r
558 }\r
559 \r
560 Private = (HTTP_BOOT_PRIVATE_DATA *) Context;\r
561\r
562 //\r
563 // Override the Maximum DHCP Message Size.\r
564 //\r
565 MaxMsgSize = HttpBootParseDhcp4Options (\r
566 Packet->Dhcp4.Option,\r
567 GET_OPTION_BUFFER_LEN (Packet),\r
568 HTTP_BOOT_DHCP4_TAG_MAXMSG\r
569 );\r
570 if (MaxMsgSize != NULL) {\r
571 Value = HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE);\r
572 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
573 }\r
574\r
575 Status = EFI_SUCCESS;\r
576 switch (Dhcp4Event) {\r
577 case Dhcp4RcvdOffer:\r
578 Status = EFI_NOT_READY;\r
579 if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {\r
580 //\r
581 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record\r
582 // the OfferIndex and OfferCount.\r
583 //\r
584 HttpBootCacheDhcp4Offer (Private, Packet);\r
585 }\r
586 break;\r
587\r
588 case Dhcp4SelectOffer:\r
589 //\r
590 // Select offer according to the priority in UEFI spec, and record the SelectIndex \r
591 // and SelectProxyType.\r
592 //\r
593 HttpBootSelectDhcp4Offer (Private);\r
594\r
595 if (Private->SelectIndex == 0) {\r
596 Status = EFI_ABORTED;\r
597 } else {\r
598 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;\r
599 }\r
600 break;\r
601 \r
602 default:\r
603 break;\r
604 }\r
605\r
606 return Status;\r
607}\r
608\r
609/**\r
610 This function will register the IPv4 gateway address to the network device.\r
611 \r
612 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
613\r
614 @retval EFI_SUCCESS The new IP configuration has been configured successfully.\r
615 @retval Others Failed to configure the address.\r
616\r
617**/\r
618EFI_STATUS\r
619HttpBootRegisterIp4Gateway (\r
620 IN HTTP_BOOT_PRIVATE_DATA *Private\r
621 )\r
622{\r
623 EFI_STATUS Status;\r
624 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
625\r
626 ASSERT (!Private->UsingIpv6);\r
627\r
628 Ip4Config2 = Private->Ip4Config2;\r
629\r
630 //\r
631 // Configure the gateway if valid.\r
632 //\r
633 if (!EFI_IP4_EQUAL (&Private->GatewayIp, &mZeroIp4Addr)) {\r
634 Status = Ip4Config2->SetData (\r
635 Ip4Config2,\r
636 Ip4Config2DataTypeGateway,\r
637 sizeof (EFI_IPv4_ADDRESS),\r
638 &Private->GatewayIp\r
639 );\r
640 if (EFI_ERROR (Status)) {\r
641 return Status;\r
642 }\r
643 }\r
644\r
645 return EFI_SUCCESS;\r
646}\r
647\r
648/**\r
649 This function will register the default DNS addresses to the network device.\r
650 \r
651 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.\r
652 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.\r
653 @param[in] DnsServerData Point a list of DNS server address in an array\r
654 of EFI_IPv4_ADDRESS instances.\r
655\r
656 @retval EFI_SUCCESS The DNS configuration has been configured successfully.\r
657 @retval Others Failed to configure the address.\r
658\r
659**/\r
660EFI_STATUS\r
661HttpBootRegisterIp4Dns (\r
662 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
663 IN UINTN DataLength,\r
664 IN VOID *DnsServerData\r
665 )\r
666{\r
667 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
668 \r
669 ASSERT (!Private->UsingIpv6);\r
670\r
671 Ip4Config2 = Private->Ip4Config2;\r
672 \r
673 return Ip4Config2->SetData (\r
674 Ip4Config2,\r
675 Ip4Config2DataTypeDnsServer,\r
676 DataLength,\r
677 DnsServerData\r
678 );\r
679}\r
680\r
681\r
682/**\r
683 This function will switch the IP4 configuration policy to Static.\r
684\r
685 @param[in] Private Pointer to HTTP boot driver private data.\r
686\r
687 @retval EFI_SUCCESS The policy is already configured to static.\r
688 @retval Others Other error as indicated..\r
689\r
690**/\r
691EFI_STATUS\r
692HttpBootSetIpPolicy (\r
693 IN HTTP_BOOT_PRIVATE_DATA *Private\r
694 )\r
695{\r
696 EFI_IP4_CONFIG2_POLICY Policy;\r
697 EFI_STATUS Status;\r
698 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
699 UINTN DataSize;\r
700\r
701 Ip4Config2 = Private->Ip4Config2;\r
702\r
703 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
704 Status = Ip4Config2->GetData (\r
705 Ip4Config2,\r
706 Ip4Config2DataTypePolicy,\r
707 &DataSize,\r
708 &Policy\r
709 );\r
710 if (EFI_ERROR (Status)) {\r
711 return Status;\r
712 }\r
713\r
714 if (Policy != Ip4Config2PolicyStatic) {\r
715 Policy = Ip4Config2PolicyStatic;\r
716 Status= Ip4Config2->SetData (\r
717 Ip4Config2,\r
718 Ip4Config2DataTypePolicy,\r
719 sizeof (EFI_IP4_CONFIG2_POLICY),\r
720 &Policy\r
721 );\r
722 if (EFI_ERROR (Status)) {\r
723 return Status;\r
724 } \r
725 }\r
726\r
727 return EFI_SUCCESS;\r
728}\r
729\r
730/**\r
731 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.\r
732\r
733 @param[in] Private Pointer to HTTP boot driver private data.\r
734\r
735 @retval EFI_SUCCESS The D.O.R.A process successfully finished.\r
736 @retval Others Failed to finish the D.O.R.A process.\r
737\r
738**/\r
739EFI_STATUS\r
740HttpBootDhcp4Dora (\r
741 IN HTTP_BOOT_PRIVATE_DATA *Private\r
742 )\r
743{\r
744 EFI_DHCP4_PROTOCOL *Dhcp4;\r
745 UINT32 OptCount;\r
746 EFI_DHCP4_PACKET_OPTION *OptList[HTTP_BOOT_DHCP4_OPTION_MAX_NUM];\r
747 UINT8 Buffer[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE];\r
748 EFI_DHCP4_CONFIG_DATA Config;\r
749 EFI_STATUS Status;\r
750 EFI_DHCP4_MODE_DATA Mode;\r
751 \r
752 Dhcp4 = Private->Dhcp4;\r
753 ASSERT (Dhcp4 != NULL);\r
754\r
755 Status = HttpBootSetIpPolicy (Private);\r
756 if (EFI_ERROR (Status)) {\r
757 return Status;\r
758 }\r
759\r
760 //\r
761 // Build option list for the request packet.\r
762 //\r
763 OptCount = HttpBootBuildDhcp4Options (Private, OptList, Buffer);\r
764 ASSERT (OptCount > 0);\r
765\r
766 ZeroMem (&Config, sizeof(Config));\r
767 Config.OptionCount = OptCount;\r
768 Config.OptionList = OptList;\r
769 Config.Dhcp4Callback = HttpBootDhcp4CallBack;\r
770 Config.CallbackContext = Private;\r
771 Config.DiscoverTryCount = HTTP_BOOT_DHCP_RETRIES;\r
772 Config.DiscoverTimeout = mHttpDhcpTimeout;\r
773\r
774 //\r
775 // Configure the DHCPv4 instance for HTTP boot.\r
776 //\r
777 Status = Dhcp4->Configure (Dhcp4, &Config);\r
778 if (EFI_ERROR (Status)) {\r
779 goto ON_EXIT;\r
780 }\r
781\r
782 //\r
783 // Initialize the record fields for DHCPv4 offer in private data.\r
784 //\r
785 Private->OfferNum = 0;\r
786 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
787 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
788\r
789 //\r
790 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.\r
791 //\r
792 Status = Dhcp4->Start (Dhcp4, NULL);\r
793 if (EFI_ERROR (Status)) {\r
794 goto ON_EXIT;\r
795 }\r
796\r
797 //\r
798 // Get the acquired IPv4 address and store them.\r
799 //\r
800 Status = Dhcp4->GetModeData (Dhcp4, &Mode);\r
801 if (EFI_ERROR (Status)) {\r
802 goto ON_EXIT;\r
803 }\r
804\r
805 ASSERT (Mode.State == Dhcp4Bound);\r
806 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
807 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
808 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
809\r
810 Status = HttpBootRegisterIp4Gateway (Private);\r
811 if (EFI_ERROR (Status)) {\r
812 goto ON_EXIT;\r
813 }\r
814\r
815 AsciiPrint ("\n Station IP address is ");\r
816 HttpBootShowIp4Addr (&Private->StationIp.v4);\r
817 AsciiPrint ("\n");\r
818\r
819ON_EXIT:\r
820 if (EFI_ERROR (Status)) {\r
821 Dhcp4->Stop (Dhcp4);\r
822 Dhcp4->Configure (Dhcp4, NULL);\r
823 } else {\r
824 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
825 Dhcp4->Configure (Dhcp4, &Config);\r
826 }\r
827\r
828 return Status;\r
829}\r