NetworkPkg: Stop and release DHCP4 child after boot info is ready
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootImpl.c
CommitLineData
c4545d76
FS
1/** @file
2 The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot.
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 Enable the use of UEFI HTTP boot function.
19
20 @param[in] Private The pointer to the driver's private data.
21
22 @retval EFI_SUCCESS HTTP boot was successfully enabled.
23 @retval EFI_INVALID_PARAMETER Private is NULL.
24 @retval EFI_ALREADY_STARTED The driver is already in started state.
25
26**/
27EFI_STATUS
28HttpBootStart (
29 IN HTTP_BOOT_PRIVATE_DATA *Private
30 )
31{
32 UINTN Index;
33
34 if (Private == NULL) {
35 return EFI_INVALID_PARAMETER;
36 }
37
38 if (Private->Started) {
39 return EFI_ALREADY_STARTED;
40 }
41
42 if (!Private->UsingIpv6) {
43 //
44 // Init the content of cached DHCP offer list.
45 //
46 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));
47 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {
48 Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_BOOT_DHCP4_PACKET_MAX_SIZE;
49 }
50 } else {
51 ASSERT (FALSE);
52 }
53
54 Private->Started = TRUE;
55
56 return EFI_SUCCESS;
57}
58
59/**
60 Attempt to complete a DHCPv4 D.O.R.A sequence to retrieve the boot resource information.
61
62 @param[in] Private The pointer to the driver's private data.
63
64 @retval EFI_SUCCESS Boot info was successfully retrieved.
65 @retval EFI_INVALID_PARAMETER Private is NULL.
66 @retval EFI_NOT_STARTED The driver is in stopped state.
67 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
68 @retval Others Other errors as indicated.
69
70**/
71EFI_STATUS
72HttpBootDhcp (
73 IN HTTP_BOOT_PRIVATE_DATA *Private
74 )
75{
76 EFI_STATUS Status;
77
78 if (Private == NULL) {
79 return EFI_INVALID_PARAMETER;
80 }
81
82 if (!Private->Started) {
83 return EFI_NOT_STARTED;
84 }
85
86 Status = EFI_DEVICE_ERROR;
87
88 if (!Private->UsingIpv6) {
89 Status = HttpBootDhcp4Dora (Private);
90 } else {
91 ASSERT (FALSE);
92 }
93
94 return Status;
95}
96
97/**
98 Attempt to download the boot file through HTTP message exchange.
99
100 @param[in] Private The pointer to the driver's private data.
101 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
102 code of EFI_SUCCESS, the amount of data transferred to
103 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
104 the size of Buffer required to retrieve the requested file.
105 @param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL,
106 then the size of the requested file is returned in
107 BufferSize.
108
109 @retval EFI_SUCCESS Boot file was loaded successfully.
110 @retval EFI_INVALID_PARAMETER Private is NULL.
111 @retval EFI_NOT_STARTED The driver is in stopped state.
112 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has
113 been updated with the size needed to complete the request.
114 @retval EFI_DEVICE_ERROR An unexpected network error occurred.
115 @retval Others Other errors as indicated.
116
117**/
118EFI_STATUS
119HttpBootLoadFile (
120 IN HTTP_BOOT_PRIVATE_DATA *Private,
121 IN OUT UINTN *BufferSize,
122 IN VOID *Buffer OPTIONAL
123 )
124{
125 EFI_STATUS Status;
126
127 if (Private == NULL) {
128 return EFI_INVALID_PARAMETER;
129 }
130
131 if (!Private->Started) {
132 return EFI_NOT_STARTED;
133 }
134
135 Status = EFI_DEVICE_ERROR;
136
137 if (Private->BootFileUri == NULL) {
138 //
139 // Parse the cached offer to get the boot file URL first.
140 //
141 Status = HttpBootDiscoverBootInfo (Private);
142 if (EFI_ERROR (Status)) {
143 return Status;
144 }
145 }
146
147 if (!Private->HttpCreated) {
148 //
149 // Create HTTP child.
150 //
151 Status = HttpBootCreateHttpIo (Private);
152 if (EFI_ERROR (Status)) {
153 return Status;
154 }
155 }
156
157 if (Private->BootFileSize == 0) {
158 //
159 // Discover the information about the bootfile if we haven't.
160 //
161
162 //
163 // Try to use HTTP HEAD method.
164 //
165 Status = HttpBootGetBootFile (
166 Private,
167 TRUE,
168 &Private->BootFileSize,
169 NULL
170 );
171 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
172 //
173 // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.
174 //
175 ASSERT (Private->BootFileSize == 0);
176 Status = HttpBootGetBootFile (
177 Private,
178 FALSE,
179 &Private->BootFileSize,
180 NULL
181 );
182 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
183 return Status;
184 }
185 }
186 }
187
188 if (*BufferSize < Private->BootFileSize) {
189 *BufferSize = Private->BootFileSize;
190 return EFI_BUFFER_TOO_SMALL;
191 }
192
193 //
194 // Load the boot file into Buffer
195 //
196 return HttpBootGetBootFile (
197 Private,
198 FALSE,
199 BufferSize,
200 Buffer
201 );
202}
203
204/**
205 Disable the use of UEFI HTTP boot function.
206
207 @param[in] Private The pointer to the driver's private data.
208
209 @retval EFI_SUCCESS HTTP boot was successfully disabled.
210 @retval EFI_NOT_STARTED The driver is already in stopped state.
211 @retval EFI_INVALID_PARAMETER Private is NULL.
212 @retval Others Unexpected error when stop the function.
213
214**/
215EFI_STATUS
216HttpBootStop (
217 IN HTTP_BOOT_PRIVATE_DATA *Private
218 )
219{
220 UINTN Index;
221
222 if (Private == NULL) {
223 return EFI_INVALID_PARAMETER;
224 }
225
226 if (!Private->Started) {
227 return EFI_NOT_STARTED;
228 }
229
230 if (Private->HttpCreated) {
231 HttpIoDestroyIo (&Private->HttpIo);
232 Private->HttpCreated = FALSE;
233 }
234
235 Private->Started = FALSE;
236 ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));
237 ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));
238 ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));
239 Private->Port = 0;
240 Private->BootFileUri = NULL;
241 Private->BootFileUriParser = NULL;
242 Private->BootFileSize = 0;
243 Private->SelectIndex = 0;
244 Private->SelectProxyType = HttpOfferTypeMax;
245
246 if (!Private->UsingIpv6) {
36673054
JW
247 //
248 // Stop and release the DHCP4 child.
249 //
250 Private->Dhcp4->Stop (Private->Dhcp4);
251 Private->Dhcp4->Configure (Private->Dhcp4, NULL);
252
c4545d76
FS
253 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {
254 if (Private->OfferBuffer[Index].Dhcp4.UriParser) {
255 HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp4.UriParser);
256 }
257 }
258 } else {
259 ASSERT (FALSE);
260 }
261
262 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));
263 Private->OfferNum = 0;
264 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
265 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
266
267 return EFI_SUCCESS;
268}
269
270/**
271 Causes the driver to load a specified file.
272
273 @param This Protocol instance pointer.
274 @param FilePath The device specific path of the file to load.
275 @param BootPolicy If TRUE, indicates that the request originates from the
276 boot manager is attempting to load FilePath as a boot
277 selection. If FALSE, then FilePath must match as exact file
278 to be loaded.
279 @param BufferSize On input the size of Buffer in bytes. On output with a return
280 code of EFI_SUCCESS, the amount of data transferred to
281 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
282 the size of Buffer required to retrieve the requested file.
283 @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
284 then the size of the requested file is returned in
285 BufferSize.
286
287 @retval EFI_SUCCESS The file was loaded.
288 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy
289 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
290 BufferSize is NULL.
291 @retval EFI_NO_MEDIA No medium was present to load the file.
292 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
293 @retval EFI_NO_RESPONSE The remote system did not respond.
294 @retval EFI_NOT_FOUND The file was not found.
295 @retval EFI_ABORTED The file load process was manually cancelled.
296 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
297 BufferSize has been updated with the size needed to complete
298 the request.
299
300**/
301EFI_STATUS
302EFIAPI
303HttpBootDxeLoadFile (
304 IN EFI_LOAD_FILE_PROTOCOL *This,
305 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
306 IN BOOLEAN BootPolicy,
307 IN OUT UINTN *BufferSize,
308 IN VOID *Buffer OPTIONAL
309 )
310{
311 HTTP_BOOT_PRIVATE_DATA *Private;
312 BOOLEAN MediaPresent;
313 EFI_STATUS Status;
314
315 if (This == NULL || BufferSize == NULL) {
316 return EFI_INVALID_PARAMETER;
317 }
318
319 //
320 // Only support BootPolicy
321 //
322 if (!BootPolicy) {
323 return EFI_UNSUPPORTED;
324 }
325
326 Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (This);
327
328 //
329 // Check media status before HTTP boot start
330 //
331 MediaPresent = TRUE;
332 NetLibDetectMedia (Private->Controller, &MediaPresent);
333 if (!MediaPresent) {
334 return EFI_NO_MEDIA;
335 }
336
337 //
338 // Initialize HTTP boot and load the boot file.
339 //
340 Status = HttpBootStart (Private);
341 if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {
342 Status = HttpBootLoadFile (Private, BufferSize, Buffer);
343 }
344
345 if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
346 HttpBootStop (Private);
36673054
JW
347 } else {
348 //
349 // Stop and release the DHCP4 child.
350 //
351 Private->Dhcp4->Stop (Private->Dhcp4);
352 Private->Dhcp4->Configure (Private->Dhcp4, NULL);
c4545d76
FS
353 }
354
355 return Status;
356}
357
358///
359/// Load File Protocol instance
360///
361GLOBAL_REMOVE_IF_UNREFERENCED
362EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {
363 HttpBootDxeLoadFile
364};