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