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