]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
BaseTools/GenFw: Disable support for R_X86_64_32S
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootSupport.c
CommitLineData
d933e70a
JW
1/** @file\r
2 Support functions implementation for UEFI HTTP boot driver.\r
3\r
f75a7f56 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
f58554fc
GB
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6This program and the accompanying materials are licensed and made available under\r
7the terms and conditions of the BSD License that accompanies this distribution.\r
d933e70a 8The full text of the license may be found at\r
f75a7f56
LG
9http://opensource.org/licenses/bsd-license.php.\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
d933e70a
JW
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "HttpBootDxe.h"\r
17\r
18\r
19/**\r
20 Get the Nic handle using any child handle in the IPv4 stack.\r
21\r
22 @param[in] ControllerHandle Pointer to child handle over IPv4.\r
23\r
24 @return NicHandle The pointer to the Nic handle.\r
25 @return NULL Can't find the Nic handle.\r
26\r
27**/\r
28EFI_HANDLE\r
29HttpBootGetNicByIp4Children (\r
30 IN EFI_HANDLE ControllerHandle\r
31 )\r
32{\r
33 EFI_HANDLE NicHandle;\r
34\r
35 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
36 if (NicHandle == NULL) {\r
37 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
38 if (NicHandle == NULL) {\r
39 return NULL;\r
40 }\r
41 }\r
42\r
43 return NicHandle;\r
44}\r
45\r
b659408b
ZL
46/**\r
47 Get the Nic handle using any child handle in the IPv6 stack.\r
48\r
49 @param[in] ControllerHandle Pointer to child handle over IPv6.\r
50\r
51 @return NicHandle The pointer to the Nic handle.\r
52 @return NULL Can't find the Nic handle.\r
53\r
54**/\r
55EFI_HANDLE\r
56HttpBootGetNicByIp6Children (\r
57 IN EFI_HANDLE ControllerHandle\r
58 )\r
59{\r
60 EFI_HANDLE NicHandle;\r
61 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
62 if (NicHandle == NULL) {\r
63 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
64 if (NicHandle == NULL) {\r
65 return NULL;\r
66 }\r
67 }\r
68\r
69 return NicHandle;\r
70}\r
d933e70a
JW
71\r
72/**\r
73 This function is to convert UINTN to ASCII string with the required formatting.\r
74\r
75 @param[in] Number Numeric value to be converted.\r
76 @param[in] Buffer The pointer to the buffer for ASCII string.\r
77 @param[in] Length The length of the required format.\r
78\r
79**/\r
80VOID\r
81HttpBootUintnToAscDecWithFormat (\r
82 IN UINTN Number,\r
83 IN UINT8 *Buffer,\r
84 IN INTN Length\r
85 )\r
86{\r
87 UINTN Remainder;\r
88\r
413535bb 89 for (; Length > 0; Length--) {\r
d933e70a
JW
90 Remainder = Number % 10;\r
91 Number /= 10;\r
413535bb 92 Buffer[Length - 1] = (UINT8) ('0' + Remainder);\r
d933e70a
JW
93 }\r
94}\r
95\r
96/**\r
97 This function is to display the IPv4 address.\r
98\r
99 @param[in] Ip The pointer to the IPv4 address.\r
100\r
101**/\r
102VOID\r
103HttpBootShowIp4Addr (\r
104 IN EFI_IPv4_ADDRESS *Ip\r
105 )\r
106{\r
107 UINTN Index;\r
108\r
109 for (Index = 0; Index < 4; Index++) {\r
110 AsciiPrint ("%d", Ip->Addr[Index]);\r
111 if (Index < 3) {\r
112 AsciiPrint (".");\r
113 }\r
114 }\r
115}\r
116\r
b659408b
ZL
117/**\r
118 This function is to display the IPv6 address.\r
119\r
120 @param[in] Ip The pointer to the IPv6 address.\r
121\r
122**/\r
123VOID\r
124HttpBootShowIp6Addr (\r
125 IN EFI_IPv6_ADDRESS *Ip\r
126 )\r
127{\r
128 UINTN Index;\r
129\r
130 for (Index = 0; Index < 16; Index++) {\r
131\r
132 if (Ip->Addr[Index] != 0) {\r
133 AsciiPrint ("%x", Ip->Addr[Index]);\r
134 }\r
135 Index++;\r
136 if (Index > 15) {\r
137 return;\r
138 }\r
139 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
140 AsciiPrint ("0");\r
141 }\r
142 AsciiPrint ("%x", Ip->Addr[Index]);\r
143 if (Index < 15) {\r
144 AsciiPrint (":");\r
145 }\r
146 }\r
147}\r
148\r
62cae351
ZL
149/**\r
150 This function is to display the HTTP error status.\r
151\r
152 @param[in] StatusCode The status code value in HTTP message.\r
153\r
154**/\r
155VOID\r
156HttpBootPrintErrorMessage (\r
157 EFI_HTTP_STATUS_CODE StatusCode\r
158 )\r
159{\r
160 AsciiPrint ("\n");\r
161\r
162 switch (StatusCode) {\r
d58bb59d 163 case HTTP_STATUS_300_MULTIPLE_CHOICES:\r
62cae351 164 AsciiPrint ("\n Redirection: 300 Multiple Choices");\r
f75a7f56
LG
165 break;\r
166\r
62cae351
ZL
167 case HTTP_STATUS_301_MOVED_PERMANENTLY:\r
168 AsciiPrint ("\n Redirection: 301 Moved Permanently");\r
f75a7f56
LG
169 break;\r
170\r
62cae351
ZL
171 case HTTP_STATUS_302_FOUND:\r
172 AsciiPrint ("\n Redirection: 302 Found");\r
f75a7f56
LG
173 break;\r
174\r
62cae351
ZL
175 case HTTP_STATUS_303_SEE_OTHER:\r
176 AsciiPrint ("\n Redirection: 303 See Other");\r
f75a7f56 177 break;\r
62cae351
ZL
178\r
179 case HTTP_STATUS_304_NOT_MODIFIED:\r
180 AsciiPrint ("\n Redirection: 304 Not Modified");\r
f75a7f56 181 break;\r
62cae351
ZL
182\r
183 case HTTP_STATUS_305_USE_PROXY:\r
184 AsciiPrint ("\n Redirection: 305 Use Proxy");\r
f75a7f56 185 break;\r
62cae351
ZL
186\r
187 case HTTP_STATUS_307_TEMPORARY_REDIRECT:\r
188 AsciiPrint ("\n Redirection: 307 Temporary Redirect");\r
406d1d92 189 break;\r
190\r
191 case HTTP_STATUS_308_PERMANENT_REDIRECT:\r
192 AsciiPrint ("\n Redirection: 308 Permanent Redirect");\r
f75a7f56 193 break;\r
62cae351
ZL
194\r
195 case HTTP_STATUS_400_BAD_REQUEST:\r
196 AsciiPrint ("\n Client Error: 400 Bad Request");\r
197 break;\r
f75a7f56 198\r
62cae351
ZL
199 case HTTP_STATUS_401_UNAUTHORIZED:\r
200 AsciiPrint ("\n Client Error: 401 Unauthorized");\r
201 break;\r
f75a7f56 202\r
62cae351
ZL
203 case HTTP_STATUS_402_PAYMENT_REQUIRED:\r
204 AsciiPrint ("\n Client Error: 402 Payment Required");\r
205 break;\r
206\r
207 case HTTP_STATUS_403_FORBIDDEN:\r
208 AsciiPrint ("\n Client Error: 403 Forbidden");\r
209 break;\r
210\r
211 case HTTP_STATUS_404_NOT_FOUND:\r
212 AsciiPrint ("\n Client Error: 404 Not Found");\r
213 break;\r
214\r
215 case HTTP_STATUS_405_METHOD_NOT_ALLOWED:\r
216 AsciiPrint ("\n Client Error: 405 Method Not Allowed");\r
217 break;\r
218\r
219 case HTTP_STATUS_406_NOT_ACCEPTABLE:\r
220 AsciiPrint ("\n Client Error: 406 Not Acceptable");\r
221 break;\r
222\r
223 case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:\r
224 AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");\r
225 break;\r
226\r
227 case HTTP_STATUS_408_REQUEST_TIME_OUT:\r
228 AsciiPrint ("\n Client Error: 408 Request Timeout");\r
229 break;\r
230\r
231 case HTTP_STATUS_409_CONFLICT:\r
232 AsciiPrint ("\n Client Error: 409 Conflict");\r
233 break;\r
234\r
235 case HTTP_STATUS_410_GONE:\r
236 AsciiPrint ("\n Client Error: 410 Gone");\r
237 break;\r
238\r
239 case HTTP_STATUS_411_LENGTH_REQUIRED:\r
240 AsciiPrint ("\n Client Error: 411 Length Required");\r
241 break;\r
242\r
243 case HTTP_STATUS_412_PRECONDITION_FAILED:\r
244 AsciiPrint ("\n Client Error: 412 Precondition Failed");\r
245 break;\r
246\r
247 case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:\r
248 AsciiPrint ("\n Client Error: 413 Request Entity Too Large");\r
249 break;\r
250\r
251 case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:\r
252 AsciiPrint ("\n Client Error: 414 Request URI Too Long");\r
253 break;\r
254\r
255 case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:\r
256 AsciiPrint ("\n Client Error: 415 Unsupported Media Type");\r
257 break;\r
258\r
259 case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:\r
260 AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");\r
261 break;\r
262\r
263 case HTTP_STATUS_417_EXPECTATION_FAILED:\r
264 AsciiPrint ("\n Client Error: 417 Expectation Failed");\r
265 break;\r
266\r
267 case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:\r
268 AsciiPrint ("\n Server Error: 500 Internal Server Error");\r
269 break;\r
270\r
271 case HTTP_STATUS_501_NOT_IMPLEMENTED:\r
272 AsciiPrint ("\n Server Error: 501 Not Implemented");\r
273 break;\r
274\r
275 case HTTP_STATUS_502_BAD_GATEWAY:\r
276 AsciiPrint ("\n Server Error: 502 Bad Gateway");\r
277 break;\r
278\r
279 case HTTP_STATUS_503_SERVICE_UNAVAILABLE:\r
280 AsciiPrint ("\n Server Error: 503 Service Unavailable");\r
281 break;\r
282\r
283 case HTTP_STATUS_504_GATEWAY_TIME_OUT:\r
284 AsciiPrint ("\n Server Error: 504 Gateway Timeout");\r
285 break;\r
286\r
287 case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:\r
288 AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");\r
289 break;\r
290\r
291 default: ;\r
f75a7f56 292\r
62cae351
ZL
293 }\r
294}\r
295\r
b659408b
ZL
296/**\r
297 Notify the callback function when an event is triggered.\r
298\r
299 @param[in] Event The triggered event.\r
300 @param[in] Context The opaque parameter to the function.\r
301\r
302**/\r
303VOID\r
304EFIAPI\r
305HttpBootCommonNotify (\r
306 IN EFI_EVENT Event,\r
307 IN VOID *Context\r
308 )\r
309{\r
310 *((BOOLEAN *) Context) = TRUE;\r
311}\r
312\r
313/**\r
314 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
315\r
316 @param[in] Private The pointer to the driver's private data.\r
317 @param[in] HostName Pointer to buffer containing hostname.\r
318 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
319\r
320 @retval EFI_SUCCESS Operation succeeded.\r
321 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
f75a7f56 322 @retval Others Other errors as indicated.\r
b659408b
ZL
323**/\r
324EFI_STATUS\r
325HttpBootDns (\r
326 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
327 IN CHAR16 *HostName,\r
f75a7f56 328 OUT EFI_IPv6_ADDRESS *IpAddress\r
b659408b
ZL
329 )\r
330{\r
331 EFI_STATUS Status;\r
332 EFI_DNS6_PROTOCOL *Dns6;\r
333 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
334 EFI_DNS6_COMPLETION_TOKEN Token;\r
335 EFI_HANDLE Dns6Handle;\r
336 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
337 EFI_IPv6_ADDRESS *DnsServerList;\r
338 UINTN DnsServerListCount;\r
339 UINTN DataSize;\r
f75a7f56
LG
340 BOOLEAN IsDone;\r
341\r
b659408b
ZL
342 DnsServerList = NULL;\r
343 DnsServerListCount = 0;\r
344 Dns6 = NULL;\r
345 Dns6Handle = NULL;\r
346 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
f75a7f56 347\r
b659408b
ZL
348 //\r
349 // Get DNS server list from EFI IPv6 Configuration protocol.\r
350 //\r
351 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
352 if (!EFI_ERROR (Status)) {\r
353 //\r
354 // Get the required size.\r
355 //\r
356 DataSize = 0;\r
357 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
358 if (Status == EFI_BUFFER_TOO_SMALL) {\r
359 DnsServerList = AllocatePool (DataSize);\r
360 if (DnsServerList == NULL) {\r
361 return EFI_OUT_OF_RESOURCES;\r
f75a7f56 362 }\r
b659408b
ZL
363\r
364 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
365 if (EFI_ERROR (Status)) {\r
366 FreePool (DnsServerList);\r
367 DnsServerList = NULL;\r
368 } else {\r
369 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
370 }\r
371 }\r
372 }\r
373 //\r
374 // Create a DNSv6 child instance and get the protocol.\r
375 //\r
376 Status = NetLibCreateServiceChild (\r
377 Private->Controller,\r
75372581 378 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
379 &gEfiDns6ServiceBindingProtocolGuid,\r
380 &Dns6Handle\r
381 );\r
382 if (EFI_ERROR (Status)) {\r
383 goto Exit;\r
f75a7f56
LG
384 }\r
385\r
b659408b
ZL
386 Status = gBS->OpenProtocol (\r
387 Dns6Handle,\r
388 &gEfiDns6ProtocolGuid,\r
389 (VOID **) &Dns6,\r
75372581 390 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
391 Private->Controller,\r
392 EFI_OPEN_PROTOCOL_BY_DRIVER\r
393 );\r
394 if (EFI_ERROR (Status)) {\r
395 goto Exit;\r
396 }\r
397\r
398 //\r
399 // Configure DNS6 instance for the DNS server address and protocol.\r
400 //\r
401 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
402 Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
403 Dns6ConfigData.DnsServerList = DnsServerList;\r
404 Dns6ConfigData.EnableDnsCache = TRUE;\r
405 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
406 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
407 Status = Dns6->Configure (\r
408 Dns6,\r
409 &Dns6ConfigData\r
410 );\r
411 if (EFI_ERROR (Status)) {\r
412 goto Exit;\r
413 }\r
f75a7f56 414\r
b659408b
ZL
415 Token.Status = EFI_NOT_READY;\r
416 IsDone = FALSE;\r
417 //\r
418 // Create event to set the IsDone flag when name resolution is finished.\r
419 //\r
420 Status = gBS->CreateEvent (\r
421 EVT_NOTIFY_SIGNAL,\r
422 TPL_NOTIFY,\r
423 HttpBootCommonNotify,\r
424 &IsDone,\r
425 &Token.Event\r
426 );\r
427 if (EFI_ERROR (Status)) {\r
428 goto Exit;\r
429 }\r
430\r
431 //\r
432 // Start asynchronous name resolution.\r
433 //\r
434 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
435 if (EFI_ERROR (Status)) {\r
436 goto Exit;\r
437 }\r
438\r
439 while (!IsDone) {\r
440 Dns6->Poll (Dns6);\r
441 }\r
f75a7f56 442\r
b659408b
ZL
443 //\r
444 // Name resolution is done, check result.\r
445 //\r
f75a7f56 446 Status = Token.Status;\r
b659408b
ZL
447 if (!EFI_ERROR (Status)) {\r
448 if (Token.RspData.H2AData == NULL) {\r
449 Status = EFI_DEVICE_ERROR;\r
450 goto Exit;\r
451 }\r
452 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
453 Status = EFI_DEVICE_ERROR;\r
454 goto Exit;\r
455 }\r
456 //\r
457 // We just return the first IPv6 address from DNS protocol.\r
458 //\r
459 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
460 Status = EFI_SUCCESS;\r
461 }\r
462Exit:\r
463\r
464 if (Token.Event != NULL) {\r
465 gBS->CloseEvent (Token.Event);\r
466 }\r
467 if (Token.RspData.H2AData != NULL) {\r
468 if (Token.RspData.H2AData->IpList != NULL) {\r
469 FreePool (Token.RspData.H2AData->IpList);\r
470 }\r
471 FreePool (Token.RspData.H2AData);\r
472 }\r
473\r
474 if (Dns6 != NULL) {\r
475 Dns6->Configure (Dns6, NULL);\r
f75a7f56 476\r
b659408b
ZL
477 gBS->CloseProtocol (\r
478 Dns6Handle,\r
479 &gEfiDns6ProtocolGuid,\r
75372581 480 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
481 Private->Controller\r
482 );\r
483 }\r
484\r
485 if (Dns6Handle != NULL) {\r
486 NetLibDestroyServiceChild (\r
487 Private->Controller,\r
75372581 488 Private->Ip6Nic->ImageHandle,\r
b659408b
ZL
489 &gEfiDns6ServiceBindingProtocolGuid,\r
490 Dns6Handle\r
491 );\r
492 }\r
493\r
494 if (DnsServerList != NULL) {\r
495 FreePool (DnsServerList);\r
496 }\r
f75a7f56
LG
497\r
498 return Status;\r
b659408b 499}\r
d933e70a
JW
500/**\r
501 Create a HTTP_IO_HEADER to hold the HTTP header items.\r
502\r
503 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.\r
504\r
505 @return A pointer of the HTTP header holder or NULL if failed.\r
f75a7f56 506\r
d933e70a
JW
507**/\r
508HTTP_IO_HEADER *\r
509HttpBootCreateHeader (\r
510 UINTN MaxHeaderCount\r
b659408b 511 )\r
d933e70a
JW
512{\r
513 HTTP_IO_HEADER *HttpIoHeader;\r
514\r
515 if (MaxHeaderCount == 0) {\r
516 return NULL;\r
517 }\r
518\r
519 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));\r
520 if (HttpIoHeader == NULL) {\r
521 return NULL;\r
522 }\r
523\r
524 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;\r
525 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);\r
526\r
527 return HttpIoHeader;\r
528}\r
529\r
530/**\r
f75a7f56 531 Destroy the HTTP_IO_HEADER and release the resouces.\r
d933e70a
JW
532\r
533 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.\r
534\r
535**/\r
536VOID\r
537HttpBootFreeHeader (\r
538 IN HTTP_IO_HEADER *HttpIoHeader\r
539 )\r
540{\r
541 UINTN Index;\r
f75a7f56 542\r
d933e70a
JW
543 if (HttpIoHeader != NULL) {\r
544 if (HttpIoHeader->HeaderCount != 0) {\r
545 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {\r
546 FreePool (HttpIoHeader->Headers[Index].FieldName);\r
547 FreePool (HttpIoHeader->Headers[Index].FieldValue);\r
548 }\r
549 }\r
550 FreePool (HttpIoHeader);\r
551 }\r
552}\r
553\r
d933e70a
JW
554/**\r
555 Set or update a HTTP header with the field name and corresponding value.\r
556\r
557 @param[in] HttpIoHeader Point to the HTTP header holder.\r
f58554fc 558 @param[in] FieldName Null terminated string which describes a field name.\r
d933e70a
JW
559 @param[in] FieldValue Null terminated string which describes the corresponding field value.\r
560\r
561 @retval EFI_SUCCESS The HTTP header has been set or updated.\r
562 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
563 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.\r
564 @retval Other Unexpected error happened.\r
f75a7f56 565\r
d933e70a
JW
566**/\r
567EFI_STATUS\r
568HttpBootSetHeader (\r
569 IN HTTP_IO_HEADER *HttpIoHeader,\r
570 IN CHAR8 *FieldName,\r
571 IN CHAR8 *FieldValue\r
572 )\r
573{\r
574 EFI_HTTP_HEADER *Header;\r
575 UINTN StrSize;\r
576 CHAR8 *NewFieldValue;\r
f75a7f56 577\r
d933e70a
JW
578 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
579 return EFI_INVALID_PARAMETER;\r
580 }\r
581\r
f58554fc 582 Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);\r
d933e70a
JW
583 if (Header == NULL) {\r
584 //\r
585 // Add a new header.\r
586 //\r
587 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {\r
588 return EFI_OUT_OF_RESOURCES;\r
589 }\r
590 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];\r
591\r
592 StrSize = AsciiStrSize (FieldName);\r
593 Header->FieldName = AllocatePool (StrSize);\r
594 if (Header->FieldName == NULL) {\r
595 return EFI_OUT_OF_RESOURCES;\r
596 }\r
597 CopyMem (Header->FieldName, FieldName, StrSize);\r
598 Header->FieldName[StrSize -1] = '\0';\r
599\r
600 StrSize = AsciiStrSize (FieldValue);\r
601 Header->FieldValue = AllocatePool (StrSize);\r
602 if (Header->FieldValue == NULL) {\r
603 FreePool (Header->FieldName);\r
604 return EFI_OUT_OF_RESOURCES;\r
605 }\r
606 CopyMem (Header->FieldValue, FieldValue, StrSize);\r
607 Header->FieldValue[StrSize -1] = '\0';\r
608\r
609 HttpIoHeader->HeaderCount++;\r
610 } else {\r
611 //\r
612 // Update an existing one.\r
613 //\r
614 StrSize = AsciiStrSize (FieldValue);\r
615 NewFieldValue = AllocatePool (StrSize);\r
616 if (NewFieldValue == NULL) {\r
617 return EFI_OUT_OF_RESOURCES;\r
618 }\r
619 CopyMem (NewFieldValue, FieldValue, StrSize);\r
620 NewFieldValue[StrSize -1] = '\0';\r
f75a7f56 621\r
d933e70a
JW
622 if (Header->FieldValue != NULL) {\r
623 FreePool (Header->FieldValue);\r
624 }\r
625 Header->FieldValue = NewFieldValue;\r
626 }\r
627\r
628 return EFI_SUCCESS;\r
629}\r
630\r
5e9e151c
JW
631/**\r
632 Notify the callback function when an event is triggered.\r
633\r
634 @param[in] Context The opaque parameter to the function.\r
635\r
636**/\r
637VOID\r
6c6452c6 638EFIAPI\r
5e9e151c
JW
639HttpIoNotifyDpc (\r
640 IN VOID *Context\r
641 )\r
642{\r
643 *((BOOLEAN *) Context) = TRUE;\r
644}\r
645\r
646/**\r
647 Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.\r
648\r
649 @param[in] Event The event signaled.\r
650 @param[in] Context The opaque parameter to the function.\r
651\r
652**/\r
653VOID\r
6c6452c6 654EFIAPI\r
5e9e151c
JW
655HttpIoNotify (\r
656 IN EFI_EVENT Event,\r
657 IN VOID *Context\r
658 )\r
659{\r
660 //\r
661 // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK\r
662 //\r
663 QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context);\r
664}\r
665\r
d933e70a
JW
666/**\r
667 Create a HTTP_IO to access the HTTP service. It will create and configure\r
668 a HTTP child handle.\r
669\r
670 @param[in] Image The handle of the driver image.\r
671 @param[in] Controller The handle of the controller.\r
672 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
673 @param[in] ConfigData The HTTP_IO configuration data.\r
95b5c32f
FS
674 @param[in] Callback Callback function which will be invoked when specified\r
675 HTTP_IO_CALLBACK_EVENT happened.\r
676 @param[in] Context The Context data which will be passed to the Callback function.\r
d933e70a 677 @param[out] HttpIo The HTTP_IO.\r
f75a7f56 678\r
d933e70a
JW
679 @retval EFI_SUCCESS The HTTP_IO is created and configured.\r
680 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
681 @retval EFI_UNSUPPORTED One or more of the control options are not\r
682 supported in the implementation.\r
683 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
684 @retval Others Failed to create the HTTP_IO or configure it.\r
685\r
686**/\r
687EFI_STATUS\r
688HttpIoCreateIo (\r
689 IN EFI_HANDLE Image,\r
690 IN EFI_HANDLE Controller,\r
691 IN UINT8 IpVersion,\r
692 IN HTTP_IO_CONFIG_DATA *ConfigData,\r
95b5c32f
FS
693 IN HTTP_IO_CALLBACK Callback,\r
694 IN VOID *Context,\r
d933e70a
JW
695 OUT HTTP_IO *HttpIo\r
696 )\r
697{\r
698 EFI_STATUS Status;\r
699 EFI_HTTP_CONFIG_DATA HttpConfigData;\r
700 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;\r
b659408b 701 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;\r
d933e70a
JW
702 EFI_HTTP_PROTOCOL *Http;\r
703 EFI_EVENT Event;\r
f75a7f56 704\r
d933e70a
JW
705 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {\r
706 return EFI_INVALID_PARAMETER;\r
707 }\r
708\r
709 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {\r
710 return EFI_UNSUPPORTED;\r
711 }\r
712\r
713 ZeroMem (HttpIo, sizeof (HTTP_IO));\r
f75a7f56 714\r
d933e70a
JW
715 //\r
716 // Create the HTTP child instance and get the HTTP protocol.\r
f75a7f56 717 //\r
d933e70a
JW
718 Status = NetLibCreateServiceChild (\r
719 Controller,\r
720 Image,\r
721 &gEfiHttpServiceBindingProtocolGuid,\r
722 &HttpIo->Handle\r
723 );\r
724 if (EFI_ERROR (Status)) {\r
725 return Status;\r
726 }\r
727\r
728 Status = gBS->OpenProtocol (\r
729 HttpIo->Handle,\r
730 &gEfiHttpProtocolGuid,\r
731 (VOID **) &Http,\r
732 Image,\r
733 Controller,\r
734 EFI_OPEN_PROTOCOL_BY_DRIVER\r
735 );\r
736 if (EFI_ERROR (Status) || (Http == NULL)) {\r
737 goto ON_ERROR;\r
738 }\r
739\r
740 //\r
741 // Init the configuration data and configure the HTTP child.\r
742 //\r
743 HttpIo->Image = Image;\r
744 HttpIo->Controller = Controller;\r
745 HttpIo->IpVersion = IpVersion;\r
746 HttpIo->Http = Http;\r
95b5c32f
FS
747 HttpIo->Callback = Callback;\r
748 HttpIo->Context = Context;\r
d933e70a
JW
749\r
750 ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));\r
751 HttpConfigData.HttpVersion = HttpVersion11;\r
752 HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;\r
753 if (HttpIo->IpVersion == IP_VERSION_4) {\r
754 HttpConfigData.LocalAddressIsIPv6 = FALSE;\r
f75a7f56 755\r
d933e70a
JW
756 Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;\r
757 Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;\r
758 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);\r
759 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
f75a7f56 760 HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint;\r
d933e70a 761 } else {\r
b659408b
ZL
762 HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
763 Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;\r
764 IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
765 HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
d933e70a 766 }\r
f75a7f56 767\r
d933e70a
JW
768 Status = Http->Configure (Http, &HttpConfigData);\r
769 if (EFI_ERROR (Status)) {\r
770 goto ON_ERROR;\r
771 }\r
772\r
773 //\r
774 // Create events for variuos asynchronous operations.\r
775 //\r
776 Status = gBS->CreateEvent (\r
777 EVT_NOTIFY_SIGNAL,\r
778 TPL_NOTIFY,\r
5e9e151c 779 HttpIoNotify,\r
d933e70a
JW
780 &HttpIo->IsTxDone,\r
781 &Event\r
782 );\r
783 if (EFI_ERROR (Status)) {\r
784 goto ON_ERROR;\r
785 }\r
786 HttpIo->ReqToken.Event = Event;\r
787 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;\r
788\r
789 Status = gBS->CreateEvent (\r
790 EVT_NOTIFY_SIGNAL,\r
791 TPL_NOTIFY,\r
5e9e151c 792 HttpIoNotify,\r
d933e70a
JW
793 &HttpIo->IsRxDone,\r
794 &Event\r
795 );\r
796 if (EFI_ERROR (Status)) {\r
797 goto ON_ERROR;\r
798 }\r
799 HttpIo->RspToken.Event = Event;\r
800 HttpIo->RspToken.Message = &HttpIo->RspMessage;\r
801\r
7570696c
JW
802 //\r
803 // Create TimeoutEvent for response\r
804 //\r
805 Status = gBS->CreateEvent (\r
806 EVT_TIMER,\r
807 TPL_CALLBACK,\r
808 NULL,\r
809 NULL,\r
810 &Event\r
811 );\r
812 if (EFI_ERROR (Status)) {\r
813 goto ON_ERROR;\r
814 }\r
815 HttpIo->TimeoutEvent = Event;\r
816\r
d933e70a 817 return EFI_SUCCESS;\r
f75a7f56 818\r
d933e70a
JW
819ON_ERROR:\r
820 HttpIoDestroyIo (HttpIo);\r
821\r
822 return Status;\r
823}\r
824\r
825/**\r
f75a7f56 826 Destroy the HTTP_IO and release the resouces.\r
d933e70a
JW
827\r
828 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.\r
829\r
830**/\r
831VOID\r
832HttpIoDestroyIo (\r
833 IN HTTP_IO *HttpIo\r
834 )\r
835{\r
836 EFI_HTTP_PROTOCOL *Http;\r
837 EFI_EVENT Event;\r
838\r
839 if (HttpIo == NULL) {\r
840 return;\r
841 }\r
842\r
843 Event = HttpIo->ReqToken.Event;\r
844 if (Event != NULL) {\r
845 gBS->CloseEvent (Event);\r
846 }\r
847\r
848 Event = HttpIo->RspToken.Event;\r
849 if (Event != NULL) {\r
850 gBS->CloseEvent (Event);\r
851 }\r
7570696c
JW
852\r
853 Event = HttpIo->TimeoutEvent;\r
854 if (Event != NULL) {\r
855 gBS->CloseEvent (Event);\r
856 }\r
f75a7f56 857\r
d933e70a
JW
858 Http = HttpIo->Http;\r
859 if (Http != NULL) {\r
860 Http->Configure (Http, NULL);\r
861 gBS->CloseProtocol (\r
862 HttpIo->Handle,\r
863 &gEfiHttpProtocolGuid,\r
864 HttpIo->Image,\r
865 HttpIo->Controller\r
866 );\r
867 }\r
868\r
869 NetLibDestroyServiceChild (\r
870 HttpIo->Controller,\r
871 HttpIo->Image,\r
872 &gEfiHttpServiceBindingProtocolGuid,\r
873 HttpIo->Handle\r
874 );\r
875}\r
876\r
877/**\r
878 Synchronously send a HTTP REQUEST message to the server.\r
f75a7f56 879\r
d933e70a
JW
880 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
881 @param[in] Request A pointer to storage such data as URL and HTTP method.\r
f75a7f56 882 @param[in] HeaderCount Number of HTTP header structures in Headers list.\r
d933e70a
JW
883 @param[in] Headers Array containing list of HTTP headers.\r
884 @param[in] BodyLength Length in bytes of the HTTP body.\r
f75a7f56
LG
885 @param[in] Body Body associated with the HTTP request.\r
886\r
d933e70a
JW
887 @retval EFI_SUCCESS The HTTP request is trasmitted.\r
888 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
889 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
890 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
891 @retval Others Other errors as indicated.\r
892\r
893**/\r
894EFI_STATUS\r
895HttpIoSendRequest (\r
896 IN HTTP_IO *HttpIo,\r
897 IN EFI_HTTP_REQUEST_DATA *Request,\r
898 IN UINTN HeaderCount,\r
899 IN EFI_HTTP_HEADER *Headers,\r
900 IN UINTN BodyLength,\r
901 IN VOID *Body\r
902 )\r
903{\r
904 EFI_STATUS Status;\r
905 EFI_HTTP_PROTOCOL *Http;\r
906\r
907 if (HttpIo == NULL || HttpIo->Http == NULL) {\r
908 return EFI_INVALID_PARAMETER;\r
909 }\r
910\r
911 HttpIo->ReqToken.Status = EFI_NOT_READY;\r
912 HttpIo->ReqToken.Message->Data.Request = Request;\r
913 HttpIo->ReqToken.Message->HeaderCount = HeaderCount;\r
914 HttpIo->ReqToken.Message->Headers = Headers;\r
915 HttpIo->ReqToken.Message->BodyLength = BodyLength;\r
916 HttpIo->ReqToken.Message->Body = Body;\r
917\r
95b5c32f
FS
918 if (HttpIo->Callback != NULL) {\r
919 Status = HttpIo->Callback (\r
920 HttpIoRequest,\r
921 HttpIo->ReqToken.Message,\r
922 HttpIo->Context\r
923 );\r
924 if (EFI_ERROR (Status)) {\r
925 return Status;\r
926 }\r
927 }\r
928\r
d933e70a
JW
929 //\r
930 // Queue the request token to HTTP instances.\r
931 //\r
932 Http = HttpIo->Http;\r
933 HttpIo->IsTxDone = FALSE;\r
934 Status = Http->Request (\r
935 Http,\r
936 &HttpIo->ReqToken\r
937 );\r
938 if (EFI_ERROR (Status)) {\r
939 return Status;\r
940 }\r
941\r
942 //\r
943 // Poll the network until transmit finish.\r
944 //\r
945 while (!HttpIo->IsTxDone) {\r
946 Http->Poll (Http);\r
947 }\r
948\r
949 return HttpIo->ReqToken.Status;\r
950}\r
951\r
952/**\r
953 Synchronously receive a HTTP RESPONSE message from the server.\r
f75a7f56 954\r
d933e70a
JW
955 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
956 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).\r
957 FALSE to continue receive the previous response message.\r
958 @param[out] ResponseData Point to a wrapper of the received response data.\r
f75a7f56 959\r
ef422fc5 960 @retval EFI_SUCCESS The HTTP response is received.\r
d933e70a
JW
961 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
962 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
963 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
964 @retval Others Other errors as indicated.\r
965\r
966**/\r
967EFI_STATUS\r
968HttpIoRecvResponse (\r
969 IN HTTP_IO *HttpIo,\r
970 IN BOOLEAN RecvMsgHeader,\r
ef422fc5 971 OUT HTTP_IO_RESPONSE_DATA *ResponseData\r
d933e70a
JW
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 EFI_HTTP_PROTOCOL *Http;\r
976\r
977 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {\r
978 return EFI_INVALID_PARAMETER;\r
979 }\r
980\r
7570696c
JW
981 //\r
982 // Start the timer, and wait Timeout seconds to receive the header packet.\r
983 //\r
984 Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HTTP_BOOT_RESPONSE_TIMEOUT * TICKS_PER_MS);\r
985 if (EFI_ERROR (Status)) {\r
986 return Status;\r
987 }\r
988\r
d933e70a
JW
989 //\r
990 // Queue the response token to HTTP instances.\r
991 //\r
992 HttpIo->RspToken.Status = EFI_NOT_READY;\r
993 if (RecvMsgHeader) {\r
994 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;\r
995 } else {\r
996 HttpIo->RspToken.Message->Data.Response = NULL;\r
997 }\r
998 HttpIo->RspToken.Message->HeaderCount = 0;\r
999 HttpIo->RspToken.Message->Headers = NULL;\r
1000 HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;\r
1001 HttpIo->RspToken.Message->Body = ResponseData->Body;\r
1002\r
1003 Http = HttpIo->Http;\r
1004 HttpIo->IsRxDone = FALSE;\r
1005 Status = Http->Response (\r
1006 Http,\r
1007 &HttpIo->RspToken\r
1008 );\r
f75a7f56 1009\r
d933e70a 1010 if (EFI_ERROR (Status)) {\r
7570696c 1011 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
d933e70a
JW
1012 return Status;\r
1013 }\r
1014\r
1015 //\r
62cae351 1016 // Poll the network until receive finish.\r
d933e70a 1017 //\r
7570696c 1018 while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL) || EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) {\r
d933e70a
JW
1019 Http->Poll (Http);\r
1020 }\r
1021\r
7570696c
JW
1022 gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);\r
1023\r
1024 if (!HttpIo->IsRxDone) {\r
1025 //\r
1026 // Timeout occurs, cancel the response token.\r
1027 //\r
1028 Http->Cancel (Http, &HttpIo->RspToken);\r
f75a7f56 1029\r
7570696c 1030 Status = EFI_TIMEOUT;\r
f75a7f56 1031\r
7570696c
JW
1032 return Status;\r
1033 } else {\r
1034 HttpIo->IsRxDone = FALSE;\r
1035 }\r
1036\r
f75a7f56 1037 if ((HttpIo->Callback != NULL) &&\r
bb4831c0 1038 (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo->RspToken.Status == EFI_HTTP_ERROR)) {\r
95b5c32f
FS
1039 Status = HttpIo->Callback (\r
1040 HttpIoResponse,\r
1041 HttpIo->RspToken.Message,\r
1042 HttpIo->Context\r
1043 );\r
1044 if (EFI_ERROR (Status)) {\r
1045 return Status;\r
1046 }\r
1047 }\r
1048\r
d933e70a
JW
1049 //\r
1050 // Store the received data into the wrapper.\r
1051 //\r
072289f4
ZL
1052 ResponseData->Status = HttpIo->RspToken.Status;\r
1053 ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
1054 ResponseData->Headers = HttpIo->RspToken.Message->Headers;\r
1055 ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;\r
d933e70a
JW
1056\r
1057 return Status;\r
1058}\r
fa848a40 1059\r
221463c2
JW
1060/**\r
1061 This function checks the HTTP(S) URI scheme.\r
1062\r
1063 @param[in] Uri The pointer to the URI string.\r
f75a7f56 1064\r
221463c2
JW
1065 @retval EFI_SUCCESS The URI scheme is valid.\r
1066 @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.\r
1067 @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071HttpBootCheckUriScheme (\r
1072 IN CHAR8 *Uri\r
1073 )\r
1074{\r
1075 UINTN Index;\r
1076 EFI_STATUS Status;\r
1077\r
1078 Status = EFI_SUCCESS;\r
1079\r
1080 //\r
1081 // Convert the scheme to all lower case.\r
1082 //\r
1083 for (Index = 0; Index < AsciiStrLen (Uri); Index++) {\r
1084 if (Uri[Index] == ':') {\r
1085 break;\r
1086 }\r
1087 if (Uri[Index] >= 'A' && Uri[Index] <= 'Z') {\r
1088 Uri[Index] -= (CHAR8)('A' - 'a');\r
1089 }\r
1090 }\r
1091\r
1092 //\r
1093 // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.\r
1094 //\r
1095 if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {\r
1096 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));\r
1097 return EFI_INVALID_PARAMETER;\r
1098 }\r
f75a7f56 1099\r
221463c2
JW
1100 //\r
1101 // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.\r
1102 //\r
1103 if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {\r
1104 DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));\r
1105 return EFI_ACCESS_DENIED;\r
1106 }\r
1107\r
1108 return Status;\r
1109}\r
1110\r
fa848a40
FS
1111/**\r
1112 Get the URI address string from the input device path.\r
1113\r
1114 Caller need to free the buffer in the UriAddress pointer.\r
f75a7f56 1115\r
fa848a40 1116 @param[in] FilePath Pointer to the device path which contains a URI device path node.\r
73617fa6 1117 @param[out] UriAddress The URI address string extract from the device path.\r
f75a7f56 1118\r
fa848a40
FS
1119 @retval EFI_SUCCESS The URI string is returned.\r
1120 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
1121\r
1122**/\r
1123EFI_STATUS\r
1124HttpBootParseFilePath (\r
1125 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1126 OUT CHAR8 **UriAddress\r
1127 )\r
1128{\r
1129 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1130 URI_DEVICE_PATH *UriDevicePath;\r
1131 CHAR8 *Uri;\r
1132 UINTN UriStrLength;\r
1133\r
1134 if (FilePath == NULL) {\r
1135 return EFI_INVALID_PARAMETER;\r
1136 }\r
1137\r
1138 *UriAddress = NULL;\r
1139\r
1140 //\r
1141 // Extract the URI address from the FilePath\r
1142 //\r
1143 TempDevicePath = FilePath;\r
1144 while (!IsDevicePathEnd (TempDevicePath)) {\r
1145 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1146 (DevicePathSubType (TempDevicePath) == MSG_URI_DP)) {\r
1147 UriDevicePath = (URI_DEVICE_PATH*) TempDevicePath;\r
1148 //\r
1149 // UEFI Spec doesn't require the URI to be a NULL-terminated string\r
1150 // So we allocate a new buffer and always append a '\0' to it.\r
1151 //\r
1152 UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
1153 if (UriStrLength == 0) {\r
1154 //\r
1155 // return a NULL UriAddress if it's a empty URI device path node.\r
1156 //\r
1157 break;\r
1158 }\r
1159 Uri = AllocatePool (UriStrLength + 1);\r
1160 if (Uri == NULL) {\r
1161 return EFI_OUT_OF_RESOURCES;\r
1162 }\r
1163 CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL));\r
1164 Uri[DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL)] = '\0';\r
1165\r
1166 *UriAddress = Uri;\r
1167 }\r
1168 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1169 }\r
1170\r
1171 return EFI_SUCCESS;\r
1172}\r
587d204c
FS
1173\r
1174/**\r
1175 This function returns the image type according to server replied HTTP message\r
1176 and also the image's URI info.\r
1177\r
1178 @param[in] Uri The pointer to the image's URI string.\r
f75a7f56
LG
1179 @param[in] UriParser URI Parse result returned by NetHttpParseUrl().\r
1180 @param[in] HeaderCount Number of HTTP header structures in Headers list.\r
587d204c
FS
1181 @param[in] Headers Array containing list of HTTP headers.\r
1182 @param[out] ImageType The image type of the downloaded file.\r
f75a7f56 1183\r
587d204c
FS
1184 @retval EFI_SUCCESS The image type is returned in ImageType.\r
1185 @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.\r
1186 @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.\r
1187 @retval EFI_NOT_FOUND Failed to identify the image type.\r
1188 @retval Others Unexpect error happened.\r
1189\r
1190**/\r
1191EFI_STATUS\r
1192HttpBootCheckImageType (\r
1193 IN CHAR8 *Uri,\r
1194 IN VOID *UriParser,\r
1195 IN UINTN HeaderCount,\r
1196 IN EFI_HTTP_HEADER *Headers,\r
1197 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
1198 )\r
1199{\r
1200 EFI_STATUS Status;\r
1201 EFI_HTTP_HEADER *Header;\r
1202 CHAR8 *FilePath;\r
1203 CHAR8 *FilePost;\r
1204\r
1205 if (Uri == NULL || UriParser == NULL || ImageType == NULL) {\r
1206 return EFI_INVALID_PARAMETER;\r
1207 }\r
1208\r
1209 if (HeaderCount != 0 && Headers == NULL) {\r
1210 return EFI_INVALID_PARAMETER;\r
1211 }\r
1212\r
1213 //\r
1214 // Determine the image type by the HTTP Content-Type header field first.\r
b173ad78
JW
1215 // "application/efi" -> EFI Image\r
1216 // "application/vnd.efi-iso" -> CD/DVD Image\r
1217 // "application/vnd.efi-img" -> Virtual Disk Image\r
587d204c
FS
1218 //\r
1219 Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);\r
1220 if (Header != NULL) {\r
1221 if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {\r
1222 *ImageType = ImageTypeEfi;\r
1223 return EFI_SUCCESS;\r
b173ad78
JW
1224 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {\r
1225 *ImageType = ImageTypeVirtualCd;\r
1226 return EFI_SUCCESS;\r
1227 } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {\r
1228 *ImageType = ImageTypeVirtualDisk;\r
1229 return EFI_SUCCESS;\r
587d204c
FS
1230 }\r
1231 }\r
1232\r
1233 //\r
1234 // Determine the image type by file extension:\r
1235 // *.efi -> EFI Image\r
1236 // *.iso -> CD/DVD Image\r
1237 // *.img -> Virtual Disk Image\r
1238 //\r
1239 Status = HttpUrlGetPath (\r
1240 Uri,\r
1241 UriParser,\r
1242 &FilePath\r
1243 );\r
1244 if (EFI_ERROR (Status)) {\r
1245 return Status;\r
1246 }\r
1247\r
1248 FilePost = FilePath + AsciiStrLen (FilePath) - 4;\r
1249 if (AsciiStrCmp (FilePost, ".efi") == 0) {\r
1250 *ImageType = ImageTypeEfi;\r
1251 } else if (AsciiStrCmp (FilePost, ".iso") == 0) {\r
1252 *ImageType = ImageTypeVirtualCd;\r
1253 } else if (AsciiStrCmp (FilePost, ".img") == 0) {\r
1254 *ImageType = ImageTypeVirtualDisk;\r
1255 } else {\r
1256 *ImageType = ImageTypeMax;\r
1257 }\r
1258\r
1259 FreePool (FilePath);\r
1260\r
1261 return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
1262}\r
1263\r
1264/**\r
1265 This function register the RAM disk info to the system.\r
f75a7f56 1266\r
587d204c
FS
1267 @param[in] Private The pointer to the driver's private data.\r
1268 @param[in] BufferSize The size of Buffer in bytes.\r
1269 @param[in] Buffer The base address of the RAM disk.\r
1270 @param[in] ImageType The image type of the file in Buffer.\r
1271\r
1272 @retval EFI_SUCCESS The RAM disk has been registered.\r
1273 @retval EFI_NOT_FOUND No RAM disk protocol instances were found.\r
1274 @retval EFI_UNSUPPORTED The ImageType is not supported.\r
1275 @retval Others Unexpected error happened.\r
1276\r
1277**/\r
1278EFI_STATUS\r
1279HttpBootRegisterRamDisk (\r
1280 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
1281 IN UINTN BufferSize,\r
1282 IN VOID *Buffer,\r
1283 IN HTTP_BOOT_IMAGE_TYPE ImageType\r
1284 )\r
1285{\r
1286 EFI_RAM_DISK_PROTOCOL *RamDisk;\r
1287 EFI_STATUS Status;\r
1288 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1289 EFI_GUID *RamDiskType;\r
f75a7f56 1290\r
587d204c
FS
1291 ASSERT (Private != NULL);\r
1292 ASSERT (Buffer != NULL);\r
1293 ASSERT (BufferSize != 0);\r
1294\r
1295 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID**) &RamDisk);\r
1296 if (EFI_ERROR (Status)) {\r
1297 DEBUG ((EFI_D_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));\r
1298 return Status;\r
1299 }\r
1300\r
1301 if (ImageType == ImageTypeVirtualCd) {\r
1302 RamDiskType = &gEfiVirtualCdGuid;\r
1303 } else if (ImageType == ImageTypeVirtualDisk) {\r
1304 RamDiskType = &gEfiVirtualDiskGuid;\r
1305 } else {\r
1306 return EFI_UNSUPPORTED;\r
1307 }\r
f75a7f56 1308\r
587d204c
FS
1309 Status = RamDisk->Register (\r
1310 (UINTN)Buffer,\r
1311 (UINT64)BufferSize,\r
1312 RamDiskType,\r
1313 Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,\r
1314 &DevicePath\r
1315 );\r
1316 if (EFI_ERROR (Status)) {\r
1317 DEBUG ((EFI_D_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));\r
1318 }\r
1319\r
1320 return Status;\r
1321}\r
1322\r
bb4831c0
FS
1323/**\r
1324 Indicate if the HTTP status code indicates a redirection.\r
f75a7f56 1325\r
bb4831c0
FS
1326 @param[in] StatusCode HTTP status code from server.\r
1327\r
1328 @return TRUE if it's redirection.\r
1329\r
1330**/\r
1331BOOLEAN\r
1332HttpBootIsHttpRedirectStatusCode (\r
1333 IN EFI_HTTP_STATUS_CODE StatusCode\r
2913ebb2 1334 )\r
bb4831c0
FS
1335{\r
1336 if (StatusCode == HTTP_STATUS_301_MOVED_PERMANENTLY ||\r
1337 StatusCode == HTTP_STATUS_302_FOUND ||\r
1338 StatusCode == HTTP_STATUS_307_TEMPORARY_REDIRECT ||\r
1339 StatusCode == HTTP_STATUS_308_PERMANENT_REDIRECT) {\r
1340 return TRUE;\r
1341 }\r
1342\r
1343 return FALSE;\r
1344}\r