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