2 Functions implementation related with DHCPv4 for HTTP boot driver.
4 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "HttpBootDxe.h"
18 // This is a map from the interested DHCP4 option tags' index to the tag value.
20 UINT8 mInterestedDhcp4Tags
[HTTP_BOOT_DHCP4_TAG_INDEX_MAX
] = {
21 DHCP4_TAG_BOOTFILE_LEN
,
25 DHCP4_TAG_VENDOR_CLASS_ID
,
31 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec.
33 UINT32 mHttpDhcpTimeout
[4] = {4, 8, 16, 32};
36 Build the options buffer for the DHCPv4 request packet.
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.
42 @return Index The count of the built-in options.
46 HttpBootBuildDhcp4Options (
47 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
48 OUT EFI_DHCP4_PACKET_OPTION
**OptList
,
52 HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt
;
57 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
60 // Append parameter request list option.
62 OptList
[Index
]->OpCode
= 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] = DHCP4_TAG_NETMASK
;
66 OptEnt
.Para
->ParaList
[1] = DHCP4_TAG_TIME_OFFSET
;
67 OptEnt
.Para
->ParaList
[2] = DHCP4_TAG_ROUTER
;
68 OptEnt
.Para
->ParaList
[3] = DHCP4_TAG_TIME_SERVER
;
69 OptEnt
.Para
->ParaList
[4] = DHCP4_TAG_NAME_SERVER
;
70 OptEnt
.Para
->ParaList
[5] = DHCP4_TAG_DNS_SERVER
;
71 OptEnt
.Para
->ParaList
[6] = DHCP4_TAG_HOSTNAME
;
72 OptEnt
.Para
->ParaList
[7] = DHCP4_TAG_BOOTFILE_LEN
;
73 OptEnt
.Para
->ParaList
[8] = DHCP4_TAG_DOMAINNAME
;
74 OptEnt
.Para
->ParaList
[9] = DHCP4_TAG_ROOTPATH
;
75 OptEnt
.Para
->ParaList
[10] = DHCP4_TAG_EXTEND_PATH
;
76 OptEnt
.Para
->ParaList
[11] = DHCP4_TAG_EMTU
;
77 OptEnt
.Para
->ParaList
[12] = DHCP4_TAG_TTL
;
78 OptEnt
.Para
->ParaList
[13] = DHCP4_TAG_BROADCAST
;
79 OptEnt
.Para
->ParaList
[14] = DHCP4_TAG_NIS_DOMAIN
;
80 OptEnt
.Para
->ParaList
[15] = DHCP4_TAG_NIS_SERVER
;
81 OptEnt
.Para
->ParaList
[16] = DHCP4_TAG_NTP_SERVER
;
82 OptEnt
.Para
->ParaList
[17] = DHCP4_TAG_VENDOR
;
83 OptEnt
.Para
->ParaList
[18] = DHCP4_TAG_REQUEST_IP
;
84 OptEnt
.Para
->ParaList
[19] = DHCP4_TAG_LEASE
;
85 OptEnt
.Para
->ParaList
[20] = DHCP4_TAG_SERVER_ID
;
86 OptEnt
.Para
->ParaList
[21] = DHCP4_TAG_T1
;
87 OptEnt
.Para
->ParaList
[22] = DHCP4_TAG_T2
;
88 OptEnt
.Para
->ParaList
[23] = DHCP4_TAG_VENDOR_CLASS_ID
;
89 OptEnt
.Para
->ParaList
[25] = DHCP4_TAG_BOOTFILE
;
90 OptEnt
.Para
->ParaList
[26] = DHCP4_TAG_UUID
;
92 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
95 // Append UUID/Guid-based client identifier option
97 OptList
[Index
]->OpCode
= 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
))) {
103 // Zero the Guid to indicate NOT programable if failed to get system Guid.
105 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
108 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
111 // Append client network device interface option
113 OptList
[Index
]->OpCode
= 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
;
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
;
122 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
123 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
124 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
128 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
131 // Append client system architecture option
133 OptList
[Index
]->OpCode
= 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
));
139 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
142 // Append vendor class identify option
144 OptList
[Index
]->OpCode
= DHCP4_TAG_VENDOR_CLASS_ID
;
145 OptList
[Index
]->Length
= (UINT8
) sizeof (HTTP_BOOT_DHCP4_OPTION_CLID
);
146 OptEnt
.Clid
= (HTTP_BOOT_DHCP4_OPTION_CLID
*) OptList
[Index
]->Data
;
149 DEFAULT_CLASS_ID_DATA
,
150 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID
)
152 HttpBootUintnToAscDecWithFormat (
153 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
,
154 OptEnt
.Clid
->ArchitectureType
,
155 sizeof (OptEnt
.Clid
->ArchitectureType
)
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
));
170 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
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.
176 @retval NULL Failed to find the required option.
177 @retval Others The position of the required option.
180 EFI_DHCP4_PACKET_OPTION
*
181 HttpBootParseDhcp4Options (
187 EFI_DHCP4_PACKET_OPTION
*Option
;
190 Option
= (EFI_DHCP4_PACKET_OPTION
*) Buffer
;
193 while (Offset
< Length
&& Option
->OpCode
!= DHCP4_TAG_EOP
) {
195 if (Option
->OpCode
== OptTag
) {
197 // Found the required option.
203 // Skip the current option to the next.
205 if (Option
->OpCode
== DHCP4_TAG_PAD
) {
208 Offset
+= Option
->Length
+ 2;
211 Option
= (EFI_DHCP4_PACKET_OPTION
*) (Buffer
+ Offset
);
218 Cache the DHCPv4 packet.
220 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
221 @param[in] Src Pointer to the DHCPv4 packet to be cached.
223 @retval EFI_SUCCESS Packet is copied.
224 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
228 HttpBootCacheDhcp4Packet (
229 IN EFI_DHCP4_PACKET
*Dst
,
230 IN EFI_DHCP4_PACKET
*Src
233 if (Dst
->Size
< Src
->Length
) {
234 return EFI_BUFFER_TOO_SMALL
;
237 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
238 Dst
->Length
= Src
->Length
;
244 Parse the cached DHCPv4 packet, including all the options.
246 @param[in] Cache4 Pointer to cached DHCPv4 packet.
248 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
249 @retval EFI_DEVICE_ERROR Failed to parse an invalid packet.
253 HttpBootParseDhcp4Packet (
254 IN HTTP_BOOT_DHCP4_PACKET_CACHE
*Cache4
257 EFI_DHCP4_PACKET
*Offer
;
258 EFI_DHCP4_PACKET_OPTION
**Options
;
260 EFI_DHCP4_PACKET_OPTION
*Option
;
261 BOOLEAN IsProxyOffer
;
264 BOOLEAN IpExpressedUri
;
267 HTTP_BOOT_OFFER_TYPE OfferType
;
268 EFI_IPv4_ADDRESS IpAddr
;
269 BOOLEAN FileFieldOverloaded
;
272 IpExpressedUri
= FALSE
;
273 IsProxyOffer
= FALSE
;
275 FileFieldOverloaded
= FALSE
;
277 ZeroMem (Cache4
->OptList
, sizeof (Cache4
->OptList
));
279 Offer
= &Cache4
->Packet
.Offer
;
280 Options
= Cache4
->OptList
;
283 // Parse DHCPv4 options in this offer, and store the pointers.
284 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
286 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
287 Options
[Index
] = HttpBootParseDhcp4Options (
289 GET_OPTION_BUFFER_LEN (Offer
),
290 mInterestedDhcp4Tags
[Index
]
294 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
295 // If yes, try to parse options from the BootFileName field, then ServerName field.
297 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD
];
298 if (Option
!= NULL
) {
299 if ((Option
->Data
[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE
) != 0) {
300 FileFieldOverloaded
= TRUE
;
301 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
302 if (Options
[Index
] == NULL
) {
303 Options
[Index
] = HttpBootParseDhcp4Options (
304 (UINT8
*) Offer
->Dhcp4
.Header
.BootFileName
,
305 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
306 mInterestedDhcp4Tags
[Index
]
311 if ((Option
->Data
[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME
) != 0) {
312 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
313 if (Options
[Index
] == NULL
) {
314 Options
[Index
] = HttpBootParseDhcp4Options (
315 (UINT8
*) Offer
->Dhcp4
.Header
.ServerName
,
316 sizeof (Offer
->Dhcp4
.Header
.ServerName
),
317 mInterestedDhcp4Tags
[Index
]
325 // The offer with "yiaddr" is a proxy offer.
327 if (Offer
->Dhcp4
.Header
.YourAddr
.Addr
[0] == 0) {
332 // The offer with "HTTPClient" is a Http offer.
334 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID
];
335 if ((Option
!= NULL
) && (Option
->Length
>= 9) &&
336 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 9) == 0)) {
341 // The offer with Domain Server is a DNS offer.
343 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER
];
344 if (Option
!= NULL
) {
349 // Parse boot file name:
350 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.
351 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.
352 // Otherwise, read from boot file field in DHCP header.
354 if (Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
356 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
357 // terminated string. So force to append null terminated character at the end of string.
359 Ptr8
= (UINT8
*)&Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
360 Ptr8
+= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
361 if (*(Ptr8
- 1) != '\0') {
364 } else if (!FileFieldOverloaded
&& Offer
->Dhcp4
.Header
.BootFileName
[0] != 0) {
366 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
367 // Do not count dhcp option header here, or else will destroy the serverhostname.
369 Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*)
370 (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
371 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
375 // Http offer must have a boot URI.
377 if (IsHttpOffer
&& Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
) {
378 return EFI_DEVICE_ERROR
;
382 // Try to retrieve the IP of HTTP server from URI.
385 Status
= HttpParseUrl (
386 (CHAR8
*) Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
,
387 (UINT32
) AsciiStrLen ((CHAR8
*) Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
),
391 if (EFI_ERROR (Status
)) {
392 return EFI_DEVICE_ERROR
;
395 Status
= HttpUrlGetIp4 (
396 (CHAR8
*) Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
,
400 IpExpressedUri
= !EFI_ERROR (Status
);
404 // Determine offer type of the DHCPv4 packet.
407 if (IpExpressedUri
) {
409 OfferType
= HttpOfferTypeProxyIpUri
;
411 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpIpUriDns
: HttpOfferTypeDhcpIpUri
;
415 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpNameUriDns
: HttpOfferTypeDhcpNameUri
;
417 OfferType
= HttpOfferTypeProxyNameUri
;
423 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpDns
: HttpOfferTypeDhcpOnly
;
425 return EFI_DEVICE_ERROR
;
429 Cache4
->OfferType
= OfferType
;
434 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
436 @param[in] Private Pointer to HTTP boot driver private data.
437 @param[in] RcvdOffer Pointer to the received offer packet.
439 @retval EFI_SUCCESS Cache and parse the packet successfully.
440 @retval Others Operation failed.
443 HttpBootCacheDhcp4Offer (
444 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
445 IN EFI_DHCP4_PACKET
*RcvdOffer
448 HTTP_BOOT_DHCP4_PACKET_CACHE
*Cache4
;
449 EFI_DHCP4_PACKET
*Offer
;
450 HTTP_BOOT_OFFER_TYPE OfferType
;
453 ASSERT (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
);
454 Cache4
= &Private
->OfferBuffer
[Private
->OfferNum
].Dhcp4
;
455 Offer
= &Cache4
->Packet
.Offer
;
458 // Cache the content of DHCPv4 packet firstly.
460 Status
= HttpBootCacheDhcp4Packet (Offer
, RcvdOffer
);
461 if (EFI_ERROR (Status
)) {
466 // Validate the DHCPv4 packet, and parse the options and offer type.
468 if (EFI_ERROR (HttpBootParseDhcp4Packet (Cache4
))) {
473 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
475 OfferType
= Cache4
->OfferType
;
476 ASSERT (OfferType
< HttpOfferTypeMax
);
477 ASSERT (Private
->OfferCount
[OfferType
] < HTTP_BOOT_OFFER_MAX_NUM
);
478 Private
->OfferIndex
[OfferType
][Private
->OfferCount
[OfferType
]] = Private
->OfferNum
;
479 Private
->OfferCount
[OfferType
]++;
486 Select an DHCPv4 or DHCP6 offer, and record SelectIndex and SelectProxyType.
488 @param[in] Private Pointer to HTTP boot driver private data.
492 HttpBootSelectDhcpOffer (
493 IN HTTP_BOOT_PRIVATE_DATA
*Private
496 Private
->SelectIndex
= 0;
497 Private
->SelectProxyType
= HttpOfferTypeMax
;
499 if (Private
->FilePathUri
!= NULL
) {
501 // We are in home environment, the URI is already specified.
502 // Just need to choose a DHCP offer.
503 // The offer with DNS server address takes priority here.
505 if (Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0) {
507 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
509 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUriDns
] > 0) {
511 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUriDns
][0] + 1;
513 } else if (Private
->OfferCount
[HttpOfferTypeDhcpNameUriDns
] > 0) {
515 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpNameUriDns
][0] + 1;
517 } else if (Private
->OfferCount
[HttpOfferTypeDhcpOnly
] > 0) {
519 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpOnly
][0] + 1;
521 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUri
] > 0) {
523 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUri
][0] + 1;
528 // We are in corporate environment.
530 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns
531 // Priority2: HttpOfferTypeDhcpNameUriDns
532 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri
533 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri
534 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri
535 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri
537 if (Private
->OfferCount
[HttpOfferTypeDhcpIpUri
] > 0) {
539 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUri
][0] + 1;
541 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUriDns
] > 0) {
543 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUriDns
][0] + 1;
545 }else if (Private
->OfferCount
[HttpOfferTypeDhcpNameUriDns
] > 0) {
547 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpNameUriDns
][0] + 1;
549 } else if (Private
->OfferCount
[HttpOfferTypeDhcpOnly
] > 0 &&
550 Private
->OfferCount
[HttpOfferTypeProxyIpUri
] > 0) {
552 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpOnly
][0] + 1;
553 Private
->SelectProxyType
= HttpOfferTypeProxyIpUri
;
555 } else if (Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0 &&
556 Private
->OfferCount
[HttpOfferTypeProxyIpUri
] > 0) {
558 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
559 Private
->SelectProxyType
= HttpOfferTypeProxyIpUri
;
561 } else if (Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0 &&
562 Private
->OfferCount
[HttpOfferTypeProxyNameUri
] > 0) {
564 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
565 Private
->SelectProxyType
= HttpOfferTypeProxyNameUri
;
567 } else if (Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0 &&
568 Private
->OfferCount
[HttpOfferTypeDhcpNameUri
] > 0) {
570 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
571 Private
->SelectProxyType
= HttpOfferTypeDhcpNameUri
;
578 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
579 to intercept events that occurred in the configuration process.
581 @param[in] This Pointer to the EFI DHCPv4 Protocol.
582 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
583 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
584 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
586 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
587 @param[out] NewPacket The packet that is used to replace the above Packet.
589 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
590 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
591 driver will continue to wait for more DHCPOFFER packets until the
592 retry timeout expires.
593 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
594 and return to the Dhcp4Init or Dhcp4InitReboot state.
599 HttpBootDhcp4CallBack (
600 IN EFI_DHCP4_PROTOCOL
*This
,
602 IN EFI_DHCP4_STATE CurrentState
,
603 IN EFI_DHCP4_EVENT Dhcp4Event
,
604 IN EFI_DHCP4_PACKET
*Packet OPTIONAL
,
605 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
608 HTTP_BOOT_PRIVATE_DATA
*Private
;
609 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
614 if ((Dhcp4Event
!= Dhcp4SendDiscover
) &&
615 (Dhcp4Event
!= Dhcp4RcvdOffer
) &&
616 (Dhcp4Event
!= Dhcp4SendRequest
) &&
617 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
618 (Dhcp4Event
!= Dhcp4SelectOffer
)) {
622 Private
= (HTTP_BOOT_PRIVATE_DATA
*) Context
;
625 // Override the Maximum DHCP Message Size.
627 MaxMsgSize
= HttpBootParseDhcp4Options (
628 Packet
->Dhcp4
.Option
,
629 GET_OPTION_BUFFER_LEN (Packet
),
632 if (MaxMsgSize
!= NULL
) {
633 Value
= HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE
);
634 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
638 // Callback to user if any packets sent or received.
640 if (Private
->HttpBootCallback
!= NULL
&& Dhcp4Event
!= Dhcp4SelectOffer
) {
641 Received
= (BOOLEAN
) (Dhcp4Event
== Dhcp4RcvdOffer
|| Dhcp4Event
== Dhcp4RcvdAck
);
642 Status
= Private
->HttpBootCallback
->Callback (
643 Private
->HttpBootCallback
,
649 if (EFI_ERROR (Status
)) {
654 Status
= EFI_SUCCESS
;
655 switch (Dhcp4Event
) {
657 Status
= EFI_NOT_READY
;
658 if (Packet
->Length
> HTTP_BOOT_DHCP4_PACKET_MAX_SIZE
) {
660 // Ignore the incoming packets which exceed the maximum length.
664 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
666 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
667 // the OfferIndex and OfferCount.
668 // If error happens, just ignore this packet and continue to wait more offer.
670 HttpBootCacheDhcp4Offer (Private
, Packet
);
674 case Dhcp4SelectOffer
:
676 // Select offer according to the priority in UEFI spec, and record the SelectIndex
677 // and SelectProxyType.
679 HttpBootSelectDhcpOffer (Private
);
681 if (Private
->SelectIndex
== 0) {
682 Status
= EFI_ABORTED
;
684 *NewPacket
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp4
.Packet
.Offer
;
696 This function will register the IPv4 gateway address to the network device.
698 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
700 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
701 @retval Others Failed to configure the address.
705 HttpBootRegisterIp4Gateway (
706 IN HTTP_BOOT_PRIVATE_DATA
*Private
710 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
712 ASSERT (!Private
->UsingIpv6
);
714 Ip4Config2
= Private
->Ip4Config2
;
717 // Configure the gateway if valid.
719 if (!EFI_IP4_EQUAL (&Private
->GatewayIp
, &mZeroIp4Addr
)) {
720 Status
= Ip4Config2
->SetData (
722 Ip4Config2DataTypeGateway
,
723 sizeof (EFI_IPv4_ADDRESS
),
726 if (EFI_ERROR (Status
)) {
735 This function will register the default DNS addresses to the network device.
737 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
738 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
739 @param[in] DnsServerData Point a list of DNS server address in an array
740 of EFI_IPv4_ADDRESS instances.
742 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
743 @retval Others Failed to configure the address.
747 HttpBootRegisterIp4Dns (
748 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
750 IN VOID
*DnsServerData
753 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
755 ASSERT (!Private
->UsingIpv6
);
757 Ip4Config2
= Private
->Ip4Config2
;
759 return Ip4Config2
->SetData (
761 Ip4Config2DataTypeDnsServer
,
769 This function will switch the IP4 configuration policy to Static.
771 @param[in] Private Pointer to HTTP boot driver private data.
773 @retval EFI_SUCCESS The policy is already configured to static.
774 @retval Others Other error as indicated..
778 HttpBootSetIp4Policy (
779 IN HTTP_BOOT_PRIVATE_DATA
*Private
782 EFI_IP4_CONFIG2_POLICY Policy
;
784 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
787 Ip4Config2
= Private
->Ip4Config2
;
789 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
790 Status
= Ip4Config2
->GetData (
792 Ip4Config2DataTypePolicy
,
796 if (EFI_ERROR (Status
)) {
800 if (Policy
!= Ip4Config2PolicyStatic
) {
801 Policy
= Ip4Config2PolicyStatic
;
802 Status
= Ip4Config2
->SetData (
804 Ip4Config2DataTypePolicy
,
805 sizeof (EFI_IP4_CONFIG2_POLICY
),
808 if (EFI_ERROR (Status
)) {
817 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.
819 @param[in] Private Pointer to HTTP boot driver private data.
821 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
822 @retval Others Failed to finish the D.O.R.A process.
827 IN HTTP_BOOT_PRIVATE_DATA
*Private
830 EFI_DHCP4_PROTOCOL
*Dhcp4
;
832 EFI_DHCP4_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP4_OPTION_MAX_NUM
];
833 UINT8 Buffer
[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE
];
834 EFI_DHCP4_CONFIG_DATA Config
;
836 EFI_DHCP4_MODE_DATA Mode
;
838 Dhcp4
= Private
->Dhcp4
;
839 ASSERT (Dhcp4
!= NULL
);
841 Status
= HttpBootSetIp4Policy (Private
);
842 if (EFI_ERROR (Status
)) {
847 // Build option list for the request packet.
849 OptCount
= HttpBootBuildDhcp4Options (Private
, OptList
, Buffer
);
850 ASSERT (OptCount
> 0);
852 ZeroMem (&Config
, sizeof(Config
));
853 Config
.OptionCount
= OptCount
;
854 Config
.OptionList
= OptList
;
855 Config
.Dhcp4Callback
= HttpBootDhcp4CallBack
;
856 Config
.CallbackContext
= Private
;
857 Config
.DiscoverTryCount
= HTTP_BOOT_DHCP_RETRIES
;
858 Config
.DiscoverTimeout
= mHttpDhcpTimeout
;
861 // Configure the DHCPv4 instance for HTTP boot.
863 Status
= Dhcp4
->Configure (Dhcp4
, &Config
);
864 if (EFI_ERROR (Status
)) {
869 // Initialize the record fields for DHCPv4 offer in private data.
871 Private
->OfferNum
= 0;
872 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
873 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
876 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
878 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
879 if (EFI_ERROR (Status
)) {
884 // Get the acquired IPv4 address and store them.
886 Status
= Dhcp4
->GetModeData (Dhcp4
, &Mode
);
887 if (EFI_ERROR (Status
)) {
891 ASSERT (Mode
.State
== Dhcp4Bound
);
892 CopyMem (&Private
->StationIp
, &Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
893 CopyMem (&Private
->SubnetMask
, &Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
894 CopyMem (&Private
->GatewayIp
, &Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
896 Status
= HttpBootRegisterIp4Gateway (Private
);
897 if (EFI_ERROR (Status
)) {
901 AsciiPrint ("\n Station IP address is ");
902 HttpBootShowIp4Addr (&Private
->StationIp
.v4
);
906 if (EFI_ERROR (Status
)) {
908 Dhcp4
->Configure (Dhcp4
, NULL
);
910 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
911 Dhcp4
->Configure (Dhcp4
, &Config
);