2 Functions implementation related with DHCPv4 for HTTP boot driver.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "HttpBootDxe.h"
12 // This is a map from the interested DHCP4 option tags' index to the tag value.
14 UINT8 mInterestedDhcp4Tags
[HTTP_BOOT_DHCP4_TAG_INDEX_MAX
] = {
15 DHCP4_TAG_BOOTFILE_LEN
,
19 DHCP4_TAG_VENDOR_CLASS_ID
,
25 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to UEFI 2.5 spec.
27 UINT32 mHttpDhcpTimeout
[4] = { 4, 8, 16, 32 };
30 Build the options buffer for the DHCPv4 request packet.
32 @param[in] Private Pointer to HTTP boot driver private data.
33 @param[out] OptList Pointer to the option pointer array.
34 @param[in] Buffer Pointer to the buffer to contain the option list.
36 @return Index The count of the built-in options.
40 HttpBootBuildDhcp4Options (
41 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
42 OUT EFI_DHCP4_PACKET_OPTION
**OptList
,
46 HTTP_BOOT_DHCP4_OPTION_ENTRY OptEnt
;
51 OptList
[0] = (EFI_DHCP4_PACKET_OPTION
*)Buffer
;
54 // Append parameter request list option.
56 OptList
[Index
]->OpCode
= DHCP4_TAG_PARA_LIST
;
57 OptList
[Index
]->Length
= 27;
58 OptEnt
.Para
= (HTTP_BOOT_DHCP4_OPTION_PARA
*)OptList
[Index
]->Data
;
59 OptEnt
.Para
->ParaList
[0] = DHCP4_TAG_NETMASK
;
60 OptEnt
.Para
->ParaList
[1] = DHCP4_TAG_TIME_OFFSET
;
61 OptEnt
.Para
->ParaList
[2] = DHCP4_TAG_ROUTER
;
62 OptEnt
.Para
->ParaList
[3] = DHCP4_TAG_TIME_SERVER
;
63 OptEnt
.Para
->ParaList
[4] = DHCP4_TAG_NAME_SERVER
;
64 OptEnt
.Para
->ParaList
[5] = DHCP4_TAG_DNS_SERVER
;
65 OptEnt
.Para
->ParaList
[6] = DHCP4_TAG_HOSTNAME
;
66 OptEnt
.Para
->ParaList
[7] = DHCP4_TAG_BOOTFILE_LEN
;
67 OptEnt
.Para
->ParaList
[8] = DHCP4_TAG_DOMAINNAME
;
68 OptEnt
.Para
->ParaList
[9] = DHCP4_TAG_ROOTPATH
;
69 OptEnt
.Para
->ParaList
[10] = DHCP4_TAG_EXTEND_PATH
;
70 OptEnt
.Para
->ParaList
[11] = DHCP4_TAG_EMTU
;
71 OptEnt
.Para
->ParaList
[12] = DHCP4_TAG_TTL
;
72 OptEnt
.Para
->ParaList
[13] = DHCP4_TAG_BROADCAST
;
73 OptEnt
.Para
->ParaList
[14] = DHCP4_TAG_NIS_DOMAIN
;
74 OptEnt
.Para
->ParaList
[15] = DHCP4_TAG_NIS_SERVER
;
75 OptEnt
.Para
->ParaList
[16] = DHCP4_TAG_NTP_SERVER
;
76 OptEnt
.Para
->ParaList
[17] = DHCP4_TAG_VENDOR
;
77 OptEnt
.Para
->ParaList
[18] = DHCP4_TAG_REQUEST_IP
;
78 OptEnt
.Para
->ParaList
[19] = DHCP4_TAG_LEASE
;
79 OptEnt
.Para
->ParaList
[20] = DHCP4_TAG_SERVER_ID
;
80 OptEnt
.Para
->ParaList
[21] = DHCP4_TAG_T1
;
81 OptEnt
.Para
->ParaList
[22] = DHCP4_TAG_T2
;
82 OptEnt
.Para
->ParaList
[23] = DHCP4_TAG_VENDOR_CLASS_ID
;
83 OptEnt
.Para
->ParaList
[25] = DHCP4_TAG_BOOTFILE
;
84 OptEnt
.Para
->ParaList
[26] = DHCP4_TAG_UUID
;
86 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
89 // Append UUID/Guid-based client identifier option
91 OptList
[Index
]->OpCode
= DHCP4_TAG_UUID
;
92 OptList
[Index
]->Length
= (UINT8
)sizeof (HTTP_BOOT_DHCP4_OPTION_UUID
);
93 OptEnt
.Uuid
= (HTTP_BOOT_DHCP4_OPTION_UUID
*)OptList
[Index
]->Data
;
94 OptEnt
.Uuid
->Type
= 0;
95 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID
*)OptEnt
.Uuid
->Guid
))) {
97 // Zero the Guid to indicate NOT programmable if failed to get system Guid.
99 ZeroMem (OptEnt
.Uuid
->Guid
, sizeof (EFI_GUID
));
103 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
106 // Append client network device interface option
108 OptList
[Index
]->OpCode
= DHCP4_TAG_UNDI
;
109 OptList
[Index
]->Length
= (UINT8
)sizeof (HTTP_BOOT_DHCP4_OPTION_UNDI
);
110 OptEnt
.Undi
= (HTTP_BOOT_DHCP4_OPTION_UNDI
*)OptList
[Index
]->Data
;
112 if (Private
->Nii
!= NULL
) {
113 OptEnt
.Undi
->Type
= Private
->Nii
->Type
;
114 OptEnt
.Undi
->MajorVer
= Private
->Nii
->MajorVer
;
115 OptEnt
.Undi
->MinorVer
= Private
->Nii
->MinorVer
;
117 OptEnt
.Undi
->Type
= DEFAULT_UNDI_TYPE
;
118 OptEnt
.Undi
->MajorVer
= DEFAULT_UNDI_MAJOR
;
119 OptEnt
.Undi
->MinorVer
= DEFAULT_UNDI_MINOR
;
123 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
126 // Append client system architecture option
128 OptList
[Index
]->OpCode
= DHCP4_TAG_ARCH
;
129 OptList
[Index
]->Length
= (UINT8
)sizeof (HTTP_BOOT_DHCP4_OPTION_ARCH
);
130 OptEnt
.Arch
= (HTTP_BOOT_DHCP4_OPTION_ARCH
*)OptList
[Index
]->Data
;
131 Value
= HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
);
132 CopyMem (&OptEnt
.Arch
->Type
, &Value
, sizeof (UINT16
));
134 OptList
[Index
] = GET_NEXT_DHCP_OPTION (OptList
[Index
- 1]);
137 // Append vendor class identify option
139 OptList
[Index
]->OpCode
= DHCP4_TAG_VENDOR_CLASS_ID
;
140 OptList
[Index
]->Length
= (UINT8
)sizeof (HTTP_BOOT_DHCP4_OPTION_CLID
);
141 OptEnt
.Clid
= (HTTP_BOOT_DHCP4_OPTION_CLID
*)OptList
[Index
]->Data
;
144 DEFAULT_CLASS_ID_DATA
,
145 sizeof (HTTP_BOOT_DHCP4_OPTION_CLID
)
147 HttpBootUintnToAscDecWithFormat (
148 EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE
,
149 OptEnt
.Clid
->ArchitectureType
,
150 sizeof (OptEnt
.Clid
->ArchitectureType
)
153 if (Private
->Nii
!= NULL
) {
154 CopyMem (OptEnt
.Clid
->InterfaceName
, Private
->Nii
->StringId
, sizeof (OptEnt
.Clid
->InterfaceName
));
155 HttpBootUintnToAscDecWithFormat (Private
->Nii
->MajorVer
, OptEnt
.Clid
->UndiMajor
, sizeof (OptEnt
.Clid
->UndiMajor
));
156 HttpBootUintnToAscDecWithFormat (Private
->Nii
->MinorVer
, OptEnt
.Clid
->UndiMinor
, sizeof (OptEnt
.Clid
->UndiMinor
));
165 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
167 @param[in] Buffer Pointer to the option buffer.
168 @param[in] Length Length of the option buffer.
169 @param[in] OptTag Tag of the required option.
171 @retval NULL Failed to find the required option.
172 @retval Others The position of the required option.
175 EFI_DHCP4_PACKET_OPTION
*
176 HttpBootParseDhcp4Options (
182 EFI_DHCP4_PACKET_OPTION
*Option
;
185 Option
= (EFI_DHCP4_PACKET_OPTION
*)Buffer
;
188 while (Offset
< Length
&& Option
->OpCode
!= DHCP4_TAG_EOP
) {
189 if (Option
->OpCode
== OptTag
) {
191 // Found the required option.
197 // Skip the current option to the next.
199 if (Option
->OpCode
== DHCP4_TAG_PAD
) {
202 Offset
+= Option
->Length
+ 2;
205 Option
= (EFI_DHCP4_PACKET_OPTION
*)(Buffer
+ Offset
);
212 Cache the DHCPv4 packet.
214 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
215 @param[in] Src Pointer to the DHCPv4 packet to be cached.
217 @retval EFI_SUCCESS Packet is copied.
218 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
222 HttpBootCacheDhcp4Packet (
223 IN EFI_DHCP4_PACKET
*Dst
,
224 IN EFI_DHCP4_PACKET
*Src
227 if (Dst
->Size
< Src
->Length
) {
228 return EFI_BUFFER_TOO_SMALL
;
231 CopyMem (&Dst
->Dhcp4
, &Src
->Dhcp4
, Src
->Length
);
232 Dst
->Length
= Src
->Length
;
238 Parse the cached DHCPv4 packet, including all the options.
240 @param[in] Cache4 Pointer to cached DHCPv4 packet.
242 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
243 @retval EFI_DEVICE_ERROR Failed to parse an invalid packet.
247 HttpBootParseDhcp4Packet (
248 IN HTTP_BOOT_DHCP4_PACKET_CACHE
*Cache4
251 EFI_DHCP4_PACKET
*Offer
;
252 EFI_DHCP4_PACKET_OPTION
**Options
;
254 EFI_DHCP4_PACKET_OPTION
*Option
;
255 BOOLEAN IsProxyOffer
;
258 BOOLEAN IpExpressedUri
;
261 HTTP_BOOT_OFFER_TYPE OfferType
;
262 EFI_IPv4_ADDRESS IpAddr
;
263 BOOLEAN FileFieldOverloaded
;
266 IpExpressedUri
= FALSE
;
267 IsProxyOffer
= FALSE
;
269 FileFieldOverloaded
= FALSE
;
271 ZeroMem (Cache4
->OptList
, sizeof (Cache4
->OptList
));
273 Offer
= &Cache4
->Packet
.Offer
;
274 Options
= Cache4
->OptList
;
277 // Parse DHCPv4 options in this offer, and store the pointers.
278 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
280 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
281 Options
[Index
] = HttpBootParseDhcp4Options (
283 GET_OPTION_BUFFER_LEN (Offer
),
284 mInterestedDhcp4Tags
[Index
]
289 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
290 // If yes, try to parse options from the BootFileName field, then ServerName field.
292 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_OVERLOAD
];
293 if (Option
!= NULL
) {
294 if ((Option
->Data
[0] & HTTP_BOOT_DHCP4_OVERLOAD_FILE
) != 0) {
295 FileFieldOverloaded
= TRUE
;
296 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
297 if (Options
[Index
] == NULL
) {
298 Options
[Index
] = HttpBootParseDhcp4Options (
299 (UINT8
*)Offer
->Dhcp4
.Header
.BootFileName
,
300 sizeof (Offer
->Dhcp4
.Header
.BootFileName
),
301 mInterestedDhcp4Tags
[Index
]
307 if ((Option
->Data
[0] & HTTP_BOOT_DHCP4_OVERLOAD_SERVER_NAME
) != 0) {
308 for (Index
= 0; Index
< HTTP_BOOT_DHCP4_TAG_INDEX_MAX
; Index
++) {
309 if (Options
[Index
] == NULL
) {
310 Options
[Index
] = HttpBootParseDhcp4Options (
311 (UINT8
*)Offer
->Dhcp4
.Header
.ServerName
,
312 sizeof (Offer
->Dhcp4
.Header
.ServerName
),
313 mInterestedDhcp4Tags
[Index
]
321 // The offer with "yiaddr" is a proxy offer.
323 if (Offer
->Dhcp4
.Header
.YourAddr
.Addr
[0] == 0) {
328 // The offer with "HTTPClient" is a Http offer.
330 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_CLASS_ID
];
331 if ((Option
!= NULL
) && (Option
->Length
>= 10) &&
332 (CompareMem (Option
->Data
, DEFAULT_CLASS_ID_DATA
, 10) == 0))
338 // The offer with Domain Server is a DNS offer.
340 Option
= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_DNS_SERVER
];
341 if (Option
!= NULL
) {
346 // Parse boot file name:
347 // Boot URI information is provided thru 'file' field in DHCP Header or option 67.
348 // According to RFC 2132, boot file name should be read from DHCP option 67 (bootfile name) if present.
349 // Otherwise, read from boot file field in DHCP header.
351 if (Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
353 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
354 // terminated string. So force to append null terminated character at the end of string.
356 Ptr8
= (UINT8
*)&Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
[0];
357 Ptr8
+= Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Length
;
358 if (*(Ptr8
- 1) != '\0') {
361 } else if (!FileFieldOverloaded
&& (Offer
->Dhcp4
.Header
.BootFileName
[0] != 0)) {
363 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
364 // Do not count dhcp option header here, or else will destroy the serverhostname.
366 Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] = (EFI_DHCP4_PACKET_OPTION
*)
367 (&Offer
->Dhcp4
.Header
.BootFileName
[0] -
368 OFFSET_OF (EFI_DHCP4_PACKET_OPTION
, Data
[0]));
372 // Http offer must have a boot URI.
374 if (IsHttpOffer
&& (Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
] == NULL
)) {
375 return EFI_DEVICE_ERROR
;
379 // Try to retrieve the IP of HTTP server from URI.
382 Status
= HttpParseUrl (
383 (CHAR8
*)Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
,
384 (UINT32
)AsciiStrLen ((CHAR8
*)Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
),
388 if (EFI_ERROR (Status
)) {
389 return EFI_DEVICE_ERROR
;
392 Status
= HttpUrlGetIp4 (
393 (CHAR8
*)Options
[HTTP_BOOT_DHCP4_TAG_INDEX_BOOTFILE
]->Data
,
397 IpExpressedUri
= !EFI_ERROR (Status
);
401 // Determine offer type of the DHCPv4 packet.
404 if (IpExpressedUri
) {
406 OfferType
= HttpOfferTypeProxyIpUri
;
408 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpIpUriDns
: HttpOfferTypeDhcpIpUri
;
412 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpNameUriDns
: HttpOfferTypeDhcpNameUri
;
414 OfferType
= HttpOfferTypeProxyNameUri
;
419 OfferType
= IsDnsOffer
? HttpOfferTypeDhcpDns
: HttpOfferTypeDhcpOnly
;
421 if (Cache4
->UriParser
!= NULL
) {
422 FreePool (Cache4
->UriParser
);
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) {
506 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
507 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUriDns
] > 0) {
508 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUriDns
][0] + 1;
509 } else if (Private
->OfferCount
[HttpOfferTypeDhcpNameUriDns
] > 0) {
510 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpNameUriDns
][0] + 1;
511 } else if (Private
->OfferCount
[HttpOfferTypeDhcpOnly
] > 0) {
512 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpOnly
][0] + 1;
513 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUri
] > 0) {
514 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUri
][0] + 1;
518 // We are in corporate environment.
520 // Priority1: HttpOfferTypeDhcpIpUri or HttpOfferTypeDhcpIpUriDns
521 // Priority2: HttpOfferTypeDhcpNameUriDns
522 // Priority3: HttpOfferTypeDhcpOnly + HttpOfferTypeProxyIpUri
523 // Priority4: HttpOfferTypeDhcpDns + HttpOfferTypeProxyIpUri
524 // Priority5: HttpOfferTypeDhcpDns + HttpOfferTypeProxyNameUri
525 // Priority6: HttpOfferTypeDhcpDns + HttpOfferTypeDhcpNameUri
527 if (Private
->OfferCount
[HttpOfferTypeDhcpIpUri
] > 0) {
528 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUri
][0] + 1;
529 } else if (Private
->OfferCount
[HttpOfferTypeDhcpIpUriDns
] > 0) {
530 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpIpUriDns
][0] + 1;
531 } else if (Private
->OfferCount
[HttpOfferTypeDhcpNameUriDns
] > 0) {
532 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpNameUriDns
][0] + 1;
533 } else if ((Private
->OfferCount
[HttpOfferTypeDhcpOnly
] > 0) &&
534 (Private
->OfferCount
[HttpOfferTypeProxyIpUri
] > 0))
536 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpOnly
][0] + 1;
537 Private
->SelectProxyType
= HttpOfferTypeProxyIpUri
;
538 } else if ((Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0) &&
539 (Private
->OfferCount
[HttpOfferTypeProxyIpUri
] > 0))
541 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
542 Private
->SelectProxyType
= HttpOfferTypeProxyIpUri
;
543 } else if ((Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0) &&
544 (Private
->OfferCount
[HttpOfferTypeProxyNameUri
] > 0))
546 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
547 Private
->SelectProxyType
= HttpOfferTypeProxyNameUri
;
548 } else if ((Private
->OfferCount
[HttpOfferTypeDhcpDns
] > 0) &&
549 (Private
->OfferCount
[HttpOfferTypeDhcpNameUri
] > 0))
551 Private
->SelectIndex
= Private
->OfferIndex
[HttpOfferTypeDhcpDns
][0] + 1;
552 Private
->SelectProxyType
= HttpOfferTypeDhcpNameUri
;
558 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
559 to intercept events that occurred in the configuration process.
561 @param[in] This Pointer to the EFI DHCPv4 Protocol.
562 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
563 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
564 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
566 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
567 @param[out] NewPacket The packet that is used to replace the above Packet.
569 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
570 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
571 driver will continue to wait for more DHCPOFFER packets until the
572 retry timeout expires.
573 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
574 and return to the Dhcp4Init or Dhcp4InitReboot state.
579 HttpBootDhcp4CallBack (
580 IN EFI_DHCP4_PROTOCOL
*This
,
582 IN EFI_DHCP4_STATE CurrentState
,
583 IN EFI_DHCP4_EVENT Dhcp4Event
,
584 IN EFI_DHCP4_PACKET
*Packet OPTIONAL
,
585 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
588 HTTP_BOOT_PRIVATE_DATA
*Private
;
589 EFI_DHCP4_PACKET_OPTION
*MaxMsgSize
;
594 if ((Dhcp4Event
!= Dhcp4SendDiscover
) &&
595 (Dhcp4Event
!= Dhcp4RcvdOffer
) &&
596 (Dhcp4Event
!= Dhcp4SendRequest
) &&
597 (Dhcp4Event
!= Dhcp4RcvdAck
) &&
598 (Dhcp4Event
!= Dhcp4SelectOffer
))
603 Private
= (HTTP_BOOT_PRIVATE_DATA
*)Context
;
606 // Override the Maximum DHCP Message Size.
608 MaxMsgSize
= HttpBootParseDhcp4Options (
609 Packet
->Dhcp4
.Option
,
610 GET_OPTION_BUFFER_LEN (Packet
),
613 if (MaxMsgSize
!= NULL
) {
614 Value
= HTONS (HTTP_BOOT_DHCP4_PACKET_MAX_SIZE
);
615 CopyMem (MaxMsgSize
->Data
, &Value
, sizeof (Value
));
619 // Callback to user if any packets sent or received.
621 if ((Private
->HttpBootCallback
!= NULL
) && (Dhcp4Event
!= Dhcp4SelectOffer
)) {
622 Received
= (BOOLEAN
)(Dhcp4Event
== Dhcp4RcvdOffer
|| Dhcp4Event
== Dhcp4RcvdAck
);
623 Status
= Private
->HttpBootCallback
->Callback (
624 Private
->HttpBootCallback
,
630 if (EFI_ERROR (Status
)) {
635 Status
= EFI_SUCCESS
;
636 switch (Dhcp4Event
) {
638 Status
= EFI_NOT_READY
;
639 if (Packet
->Length
> HTTP_BOOT_DHCP4_PACKET_MAX_SIZE
) {
641 // Ignore the incoming packets which exceed the maximum length.
646 if (Private
->OfferNum
< HTTP_BOOT_OFFER_MAX_NUM
) {
648 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
649 // the OfferIndex and OfferCount.
650 // If error happens, just ignore this packet and continue to wait more offer.
652 HttpBootCacheDhcp4Offer (Private
, Packet
);
657 case Dhcp4SelectOffer
:
659 // Select offer according to the priority in UEFI spec, and record the SelectIndex
660 // and SelectProxyType.
662 HttpBootSelectDhcpOffer (Private
);
664 if (Private
->SelectIndex
== 0) {
665 Status
= EFI_ABORTED
;
667 *NewPacket
= &Private
->OfferBuffer
[Private
->SelectIndex
- 1].Dhcp4
.Packet
.Offer
;
680 This function will register the IPv4 gateway address to the network device.
682 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
684 @retval EFI_SUCCESS The new IP configuration has been configured successfully.
685 @retval Others Failed to configure the address.
689 HttpBootRegisterIp4Gateway (
690 IN HTTP_BOOT_PRIVATE_DATA
*Private
694 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
696 ASSERT (!Private
->UsingIpv6
);
698 Ip4Config2
= Private
->Ip4Config2
;
701 // Configure the gateway if valid.
703 if (!EFI_IP4_EQUAL (&Private
->GatewayIp
, &mZeroIp4Addr
)) {
704 Status
= Ip4Config2
->SetData (
706 Ip4Config2DataTypeGateway
,
707 sizeof (EFI_IPv4_ADDRESS
),
710 if (EFI_ERROR (Status
)) {
719 This function will register the default DNS addresses to the network device.
721 @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
722 @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
723 @param[in] DnsServerData Point a list of DNS server address in an array
724 of EFI_IPv4_ADDRESS instances.
726 @retval EFI_SUCCESS The DNS configuration has been configured successfully.
727 @retval Others Failed to configure the address.
731 HttpBootRegisterIp4Dns (
732 IN HTTP_BOOT_PRIVATE_DATA
*Private
,
734 IN VOID
*DnsServerData
737 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
739 ASSERT (!Private
->UsingIpv6
);
741 Ip4Config2
= Private
->Ip4Config2
;
743 return Ip4Config2
->SetData (
745 Ip4Config2DataTypeDnsServer
,
752 This function will switch the IP4 configuration policy to Static.
754 @param[in] Private Pointer to HTTP boot driver private data.
756 @retval EFI_SUCCESS The policy is already configured to static.
757 @retval Others Other error as indicated..
761 HttpBootSetIp4Policy (
762 IN HTTP_BOOT_PRIVATE_DATA
*Private
765 EFI_IP4_CONFIG2_POLICY Policy
;
767 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
770 Ip4Config2
= Private
->Ip4Config2
;
772 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
773 Status
= Ip4Config2
->GetData (
775 Ip4Config2DataTypePolicy
,
779 if (EFI_ERROR (Status
)) {
783 if (Policy
!= Ip4Config2PolicyStatic
) {
784 Policy
= Ip4Config2PolicyStatic
;
785 Status
= Ip4Config2
->SetData (
787 Ip4Config2DataTypePolicy
,
788 sizeof (EFI_IP4_CONFIG2_POLICY
),
791 if (EFI_ERROR (Status
)) {
800 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other Http boot information.
802 @param[in] Private Pointer to HTTP boot driver private data.
804 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
805 @retval Others Failed to finish the D.O.R.A process.
810 IN HTTP_BOOT_PRIVATE_DATA
*Private
813 EFI_DHCP4_PROTOCOL
*Dhcp4
;
815 EFI_DHCP4_PACKET_OPTION
*OptList
[HTTP_BOOT_DHCP4_OPTION_MAX_NUM
];
816 UINT8 Buffer
[HTTP_BOOT_DHCP4_OPTION_MAX_SIZE
];
817 EFI_DHCP4_CONFIG_DATA Config
;
819 EFI_DHCP4_MODE_DATA Mode
;
821 Dhcp4
= Private
->Dhcp4
;
822 ASSERT (Dhcp4
!= NULL
);
824 Status
= HttpBootSetIp4Policy (Private
);
825 if (EFI_ERROR (Status
)) {
830 // Build option list for the request packet.
832 OptCount
= HttpBootBuildDhcp4Options (Private
, OptList
, Buffer
);
833 ASSERT (OptCount
> 0);
835 ZeroMem (&Config
, sizeof (Config
));
836 Config
.OptionCount
= OptCount
;
837 Config
.OptionList
= OptList
;
838 Config
.Dhcp4Callback
= HttpBootDhcp4CallBack
;
839 Config
.CallbackContext
= Private
;
840 Config
.DiscoverTryCount
= HTTP_BOOT_DHCP_RETRIES
;
841 Config
.DiscoverTimeout
= mHttpDhcpTimeout
;
844 // Configure the DHCPv4 instance for HTTP boot.
846 Status
= Dhcp4
->Configure (Dhcp4
, &Config
);
847 if (EFI_ERROR (Status
)) {
852 // Initialize the record fields for DHCPv4 offer in private data.
854 Private
->OfferNum
= 0;
855 ZeroMem (Private
->OfferCount
, sizeof (Private
->OfferCount
));
856 ZeroMem (Private
->OfferIndex
, sizeof (Private
->OfferIndex
));
859 // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
861 Status
= Dhcp4
->Start (Dhcp4
, NULL
);
862 if (EFI_ERROR (Status
)) {
867 // Get the acquired IPv4 address and store them.
869 Status
= Dhcp4
->GetModeData (Dhcp4
, &Mode
);
870 if (EFI_ERROR (Status
)) {
874 ASSERT (Mode
.State
== Dhcp4Bound
);
875 CopyMem (&Private
->StationIp
, &Mode
.ClientAddress
, sizeof (EFI_IPv4_ADDRESS
));
876 CopyMem (&Private
->SubnetMask
, &Mode
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
877 CopyMem (&Private
->GatewayIp
, &Mode
.RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
879 Status
= HttpBootRegisterIp4Gateway (Private
);
880 if (EFI_ERROR (Status
)) {
884 AsciiPrint ("\n Station IP address is ");
885 HttpBootShowIp4Addr (&Private
->StationIp
.v4
);
889 if (EFI_ERROR (Status
)) {
891 Dhcp4
->Configure (Dhcp4
, NULL
);
893 ZeroMem (&Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
894 Dhcp4
->Configure (Dhcp4
, &Config
);