]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
NetworkPkg: Use the New Functions from HttpLib
[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
072289f4 4Copyright (c) 2015 - 2016, 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
JW
8The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php. \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
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
89 while (Length > 0) {\r
90 Length--;\r
91 Remainder = Number % 10;\r
92 Number /= 10;\r
93 Buffer[Length] = (UINT8) ('0' + Remainder);\r
94 }\r
95}\r
96\r
97/**\r
98 This function is to display the IPv4 address.\r
99\r
100 @param[in] Ip The pointer to the IPv4 address.\r
101\r
102**/\r
103VOID\r
104HttpBootShowIp4Addr (\r
105 IN EFI_IPv4_ADDRESS *Ip\r
106 )\r
107{\r
108 UINTN Index;\r
109\r
110 for (Index = 0; Index < 4; Index++) {\r
111 AsciiPrint ("%d", Ip->Addr[Index]);\r
112 if (Index < 3) {\r
113 AsciiPrint (".");\r
114 }\r
115 }\r
116}\r
117\r
b659408b
ZL
118/**\r
119 This function is to display the IPv6 address.\r
120\r
121 @param[in] Ip The pointer to the IPv6 address.\r
122\r
123**/\r
124VOID\r
125HttpBootShowIp6Addr (\r
126 IN EFI_IPv6_ADDRESS *Ip\r
127 )\r
128{\r
129 UINTN Index;\r
130\r
131 for (Index = 0; Index < 16; Index++) {\r
132\r
133 if (Ip->Addr[Index] != 0) {\r
134 AsciiPrint ("%x", Ip->Addr[Index]);\r
135 }\r
136 Index++;\r
137 if (Index > 15) {\r
138 return;\r
139 }\r
140 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
141 AsciiPrint ("0");\r
142 }\r
143 AsciiPrint ("%x", Ip->Addr[Index]);\r
144 if (Index < 15) {\r
145 AsciiPrint (":");\r
146 }\r
147 }\r
148}\r
149\r
62cae351
ZL
150/**\r
151 This function is to display the HTTP error status.\r
152\r
153 @param[in] StatusCode The status code value in HTTP message.\r
154\r
155**/\r
156VOID\r
157HttpBootPrintErrorMessage (\r
158 EFI_HTTP_STATUS_CODE StatusCode\r
159 )\r
160{\r
161 AsciiPrint ("\n");\r
162\r
163 switch (StatusCode) {\r
164 case HTTP_STATUS_300_MULTIPLE_CHIOCES:\r
165 AsciiPrint ("\n Redirection: 300 Multiple Choices");\r
166 break; \r
167 \r
168 case HTTP_STATUS_301_MOVED_PERMANENTLY:\r
169 AsciiPrint ("\n Redirection: 301 Moved Permanently");\r
170 break; \r
171 \r
172 case HTTP_STATUS_302_FOUND:\r
173 AsciiPrint ("\n Redirection: 302 Found");\r
174 break; \r
175 \r
176 case HTTP_STATUS_303_SEE_OTHER:\r
177 AsciiPrint ("\n Redirection: 303 See Other");\r
178 break; \r
179\r
180 case HTTP_STATUS_304_NOT_MODIFIED:\r
181 AsciiPrint ("\n Redirection: 304 Not Modified");\r
182 break; \r
183\r
184 case HTTP_STATUS_305_USE_PROXY:\r
185 AsciiPrint ("\n Redirection: 305 Use Proxy");\r
186 break; \r
187\r
188 case HTTP_STATUS_307_TEMPORARY_REDIRECT:\r
189 AsciiPrint ("\n Redirection: 307 Temporary Redirect");\r
190 break; \r
191\r
192 case HTTP_STATUS_400_BAD_REQUEST:\r
193 AsciiPrint ("\n Client Error: 400 Bad Request");\r
194 break;\r
195 \r
196 case HTTP_STATUS_401_UNAUTHORIZED:\r
197 AsciiPrint ("\n Client Error: 401 Unauthorized");\r
198 break;\r
199 \r
200 case HTTP_STATUS_402_PAYMENT_REQUIRED:\r
201 AsciiPrint ("\n Client Error: 402 Payment Required");\r
202 break;\r
203\r
204 case HTTP_STATUS_403_FORBIDDEN:\r
205 AsciiPrint ("\n Client Error: 403 Forbidden");\r
206 break;\r
207\r
208 case HTTP_STATUS_404_NOT_FOUND:\r
209 AsciiPrint ("\n Client Error: 404 Not Found");\r
210 break;\r
211\r
212 case HTTP_STATUS_405_METHOD_NOT_ALLOWED:\r
213 AsciiPrint ("\n Client Error: 405 Method Not Allowed");\r
214 break;\r
215\r
216 case HTTP_STATUS_406_NOT_ACCEPTABLE:\r
217 AsciiPrint ("\n Client Error: 406 Not Acceptable");\r
218 break;\r
219\r
220 case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:\r
221 AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");\r
222 break;\r
223\r
224 case HTTP_STATUS_408_REQUEST_TIME_OUT:\r
225 AsciiPrint ("\n Client Error: 408 Request Timeout");\r
226 break;\r
227\r
228 case HTTP_STATUS_409_CONFLICT:\r
229 AsciiPrint ("\n Client Error: 409 Conflict");\r
230 break;\r
231\r
232 case HTTP_STATUS_410_GONE:\r
233 AsciiPrint ("\n Client Error: 410 Gone");\r
234 break;\r
235\r
236 case HTTP_STATUS_411_LENGTH_REQUIRED:\r
237 AsciiPrint ("\n Client Error: 411 Length Required");\r
238 break;\r
239\r
240 case HTTP_STATUS_412_PRECONDITION_FAILED:\r
241 AsciiPrint ("\n Client Error: 412 Precondition Failed");\r
242 break;\r
243\r
244 case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:\r
245 AsciiPrint ("\n Client Error: 413 Request Entity Too Large");\r
246 break;\r
247\r
248 case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:\r
249 AsciiPrint ("\n Client Error: 414 Request URI Too Long");\r
250 break;\r
251\r
252 case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:\r
253 AsciiPrint ("\n Client Error: 415 Unsupported Media Type");\r
254 break;\r
255\r
256 case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:\r
257 AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");\r
258 break;\r
259\r
260 case HTTP_STATUS_417_EXPECTATION_FAILED:\r
261 AsciiPrint ("\n Client Error: 417 Expectation Failed");\r
262 break;\r
263\r
264 case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:\r
265 AsciiPrint ("\n Server Error: 500 Internal Server Error");\r
266 break;\r
267\r
268 case HTTP_STATUS_501_NOT_IMPLEMENTED:\r
269 AsciiPrint ("\n Server Error: 501 Not Implemented");\r
270 break;\r
271\r
272 case HTTP_STATUS_502_BAD_GATEWAY:\r
273 AsciiPrint ("\n Server Error: 502 Bad Gateway");\r
274 break;\r
275\r
276 case HTTP_STATUS_503_SERVICE_UNAVAILABLE:\r
277 AsciiPrint ("\n Server Error: 503 Service Unavailable");\r
278 break;\r
279\r
280 case HTTP_STATUS_504_GATEWAY_TIME_OUT:\r
281 AsciiPrint ("\n Server Error: 504 Gateway Timeout");\r
282 break;\r
283\r
284 case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:\r
285 AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");\r
286 break;\r
287\r
288 default: ;\r
289 \r
290 }\r
291}\r
292\r
b659408b
ZL
293/**\r
294 Notify the callback function when an event is triggered.\r
295\r
296 @param[in] Event The triggered event.\r
297 @param[in] Context The opaque parameter to the function.\r
298\r
299**/\r
300VOID\r
301EFIAPI\r
302HttpBootCommonNotify (\r
303 IN EFI_EVENT Event,\r
304 IN VOID *Context\r
305 )\r
306{\r
307 *((BOOLEAN *) Context) = TRUE;\r
308}\r
309\r
310/**\r
311 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
312\r
313 @param[in] Private The pointer to the driver's private data.\r
314 @param[in] HostName Pointer to buffer containing hostname.\r
315 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
316\r
317 @retval EFI_SUCCESS Operation succeeded.\r
318 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
319 @retval Others Other errors as indicated. \r
320**/\r
321EFI_STATUS\r
322HttpBootDns (\r
323 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
324 IN CHAR16 *HostName,\r
325 OUT EFI_IPv6_ADDRESS *IpAddress \r
326 )\r
327{\r
328 EFI_STATUS Status;\r
329 EFI_DNS6_PROTOCOL *Dns6;\r
330 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
331 EFI_DNS6_COMPLETION_TOKEN Token;\r
332 EFI_HANDLE Dns6Handle;\r
333 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
334 EFI_IPv6_ADDRESS *DnsServerList;\r
335 UINTN DnsServerListCount;\r
336 UINTN DataSize;\r
337 BOOLEAN IsDone; \r
338 \r
339 DnsServerList = NULL;\r
340 DnsServerListCount = 0;\r
341 Dns6 = NULL;\r
342 Dns6Handle = NULL;\r
343 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
344 \r
345 //\r
346 // Get DNS server list from EFI IPv6 Configuration protocol.\r
347 //\r
348 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
349 if (!EFI_ERROR (Status)) {\r
350 //\r
351 // Get the required size.\r
352 //\r
353 DataSize = 0;\r
354 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
355 if (Status == EFI_BUFFER_TOO_SMALL) {\r
356 DnsServerList = AllocatePool (DataSize);\r
357 if (DnsServerList == NULL) {\r
358 return EFI_OUT_OF_RESOURCES;\r
359 } \r
360\r
361 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
362 if (EFI_ERROR (Status)) {\r
363 FreePool (DnsServerList);\r
364 DnsServerList = NULL;\r
365 } else {\r
366 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
367 }\r
368 }\r
369 }\r
370 //\r
371 // Create a DNSv6 child instance and get the protocol.\r
372 //\r
373 Status = NetLibCreateServiceChild (\r
374 Private->Controller,\r
375 Private->Image,\r
376 &gEfiDns6ServiceBindingProtocolGuid,\r
377 &Dns6Handle\r
378 );\r
379 if (EFI_ERROR (Status)) {\r
380 goto Exit;\r
381 } \r
382 \r
383 Status = gBS->OpenProtocol (\r
384 Dns6Handle,\r
385 &gEfiDns6ProtocolGuid,\r
386 (VOID **) &Dns6,\r
387 Private->Image,\r
388 Private->Controller,\r
389 EFI_OPEN_PROTOCOL_BY_DRIVER\r
390 );\r
391 if (EFI_ERROR (Status)) {\r
392 goto Exit;\r
393 }\r
394\r
395 //\r
396 // Configure DNS6 instance for the DNS server address and protocol.\r
397 //\r
398 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
399 Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
400 Dns6ConfigData.DnsServerList = DnsServerList;\r
401 Dns6ConfigData.EnableDnsCache = TRUE;\r
402 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
403 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
404 Status = Dns6->Configure (\r
405 Dns6,\r
406 &Dns6ConfigData\r
407 );\r
408 if (EFI_ERROR (Status)) {\r
409 goto Exit;\r
410 }\r
411 \r
412 Token.Status = EFI_NOT_READY;\r
413 IsDone = FALSE;\r
414 //\r
415 // Create event to set the IsDone flag when name resolution is finished.\r
416 //\r
417 Status = gBS->CreateEvent (\r
418 EVT_NOTIFY_SIGNAL,\r
419 TPL_NOTIFY,\r
420 HttpBootCommonNotify,\r
421 &IsDone,\r
422 &Token.Event\r
423 );\r
424 if (EFI_ERROR (Status)) {\r
425 goto Exit;\r
426 }\r
427\r
428 //\r
429 // Start asynchronous name resolution.\r
430 //\r
431 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
432 if (EFI_ERROR (Status)) {\r
433 goto Exit;\r
434 }\r
435\r
436 while (!IsDone) {\r
437 Dns6->Poll (Dns6);\r
438 }\r
439 \r
440 //\r
441 // Name resolution is done, check result.\r
442 //\r
443 Status = Token.Status; \r
444 if (!EFI_ERROR (Status)) {\r
445 if (Token.RspData.H2AData == NULL) {\r
446 Status = EFI_DEVICE_ERROR;\r
447 goto Exit;\r
448 }\r
449 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
450 Status = EFI_DEVICE_ERROR;\r
451 goto Exit;\r
452 }\r
453 //\r
454 // We just return the first IPv6 address from DNS protocol.\r
455 //\r
456 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
457 Status = EFI_SUCCESS;\r
458 }\r
459Exit:\r
460\r
461 if (Token.Event != NULL) {\r
462 gBS->CloseEvent (Token.Event);\r
463 }\r
464 if (Token.RspData.H2AData != NULL) {\r
465 if (Token.RspData.H2AData->IpList != NULL) {\r
466 FreePool (Token.RspData.H2AData->IpList);\r
467 }\r
468 FreePool (Token.RspData.H2AData);\r
469 }\r
470\r
471 if (Dns6 != NULL) {\r
472 Dns6->Configure (Dns6, NULL);\r
473 \r
474 gBS->CloseProtocol (\r
475 Dns6Handle,\r
476 &gEfiDns6ProtocolGuid,\r
477 Private->Image,\r
478 Private->Controller\r
479 );\r
480 }\r
481\r
482 if (Dns6Handle != NULL) {\r
483 NetLibDestroyServiceChild (\r
484 Private->Controller,\r
485 Private->Image,\r
486 &gEfiDns6ServiceBindingProtocolGuid,\r
487 Dns6Handle\r
488 );\r
489 }\r
490\r
491 if (DnsServerList != NULL) {\r
492 FreePool (DnsServerList);\r
493 }\r
494 \r
495 return Status; \r
496}\r
d933e70a
JW
497/**\r
498 Create a HTTP_IO_HEADER to hold the HTTP header items.\r
499\r
500 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.\r
501\r
502 @return A pointer of the HTTP header holder or NULL if failed.\r
503 \r
504**/\r
505HTTP_IO_HEADER *\r
506HttpBootCreateHeader (\r
507 UINTN MaxHeaderCount\r
b659408b 508 )\r
d933e70a
JW
509{\r
510 HTTP_IO_HEADER *HttpIoHeader;\r
511\r
512 if (MaxHeaderCount == 0) {\r
513 return NULL;\r
514 }\r
515\r
516 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));\r
517 if (HttpIoHeader == NULL) {\r
518 return NULL;\r
519 }\r
520\r
521 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;\r
522 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);\r
523\r
524 return HttpIoHeader;\r
525}\r
526\r
527/**\r
528 Destroy the HTTP_IO_HEADER and release the resouces. \r
529\r
530 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.\r
531\r
532**/\r
533VOID\r
534HttpBootFreeHeader (\r
535 IN HTTP_IO_HEADER *HttpIoHeader\r
536 )\r
537{\r
538 UINTN Index;\r
539 \r
540 if (HttpIoHeader != NULL) {\r
541 if (HttpIoHeader->HeaderCount != 0) {\r
542 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {\r
543 FreePool (HttpIoHeader->Headers[Index].FieldName);\r
544 FreePool (HttpIoHeader->Headers[Index].FieldValue);\r
545 }\r
546 }\r
547 FreePool (HttpIoHeader);\r
548 }\r
549}\r
550\r
d933e70a
JW
551/**\r
552 Set or update a HTTP header with the field name and corresponding value.\r
553\r
554 @param[in] HttpIoHeader Point to the HTTP header holder.\r
f58554fc 555 @param[in] FieldName Null terminated string which describes a field name.\r
d933e70a
JW
556 @param[in] FieldValue Null terminated string which describes the corresponding field value.\r
557\r
558 @retval EFI_SUCCESS The HTTP header has been set or updated.\r
559 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
560 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.\r
561 @retval Other Unexpected error happened.\r
562 \r
563**/\r
564EFI_STATUS\r
565HttpBootSetHeader (\r
566 IN HTTP_IO_HEADER *HttpIoHeader,\r
567 IN CHAR8 *FieldName,\r
568 IN CHAR8 *FieldValue\r
569 )\r
570{\r
571 EFI_HTTP_HEADER *Header;\r
572 UINTN StrSize;\r
573 CHAR8 *NewFieldValue;\r
574 \r
575 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
576 return EFI_INVALID_PARAMETER;\r
577 }\r
578\r
f58554fc 579 Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);\r
d933e70a
JW
580 if (Header == NULL) {\r
581 //\r
582 // Add a new header.\r
583 //\r
584 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {\r
585 return EFI_OUT_OF_RESOURCES;\r
586 }\r
587 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];\r
588\r
589 StrSize = AsciiStrSize (FieldName);\r
590 Header->FieldName = AllocatePool (StrSize);\r
591 if (Header->FieldName == NULL) {\r
592 return EFI_OUT_OF_RESOURCES;\r
593 }\r
594 CopyMem (Header->FieldName, FieldName, StrSize);\r
595 Header->FieldName[StrSize -1] = '\0';\r
596\r
597 StrSize = AsciiStrSize (FieldValue);\r
598 Header->FieldValue = AllocatePool (StrSize);\r
599 if (Header->FieldValue == NULL) {\r
600 FreePool (Header->FieldName);\r
601 return EFI_OUT_OF_RESOURCES;\r
602 }\r
603 CopyMem (Header->FieldValue, FieldValue, StrSize);\r
604 Header->FieldValue[StrSize -1] = '\0';\r
605\r
606 HttpIoHeader->HeaderCount++;\r
607 } else {\r
608 //\r
609 // Update an existing one.\r
610 //\r
611 StrSize = AsciiStrSize (FieldValue);\r
612 NewFieldValue = AllocatePool (StrSize);\r
613 if (NewFieldValue == NULL) {\r
614 return EFI_OUT_OF_RESOURCES;\r
615 }\r
616 CopyMem (NewFieldValue, FieldValue, StrSize);\r
617 NewFieldValue[StrSize -1] = '\0';\r
618 \r
619 if (Header->FieldValue != NULL) {\r
620 FreePool (Header->FieldValue);\r
621 }\r
622 Header->FieldValue = NewFieldValue;\r
623 }\r
624\r
625 return EFI_SUCCESS;\r
626}\r
627\r
d933e70a
JW
628/**\r
629 Create a HTTP_IO to access the HTTP service. It will create and configure\r
630 a HTTP child handle.\r
631\r
632 @param[in] Image The handle of the driver image.\r
633 @param[in] Controller The handle of the controller.\r
634 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
635 @param[in] ConfigData The HTTP_IO configuration data.\r
636 @param[out] HttpIo The HTTP_IO.\r
637 \r
638 @retval EFI_SUCCESS The HTTP_IO is created and configured.\r
639 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
640 @retval EFI_UNSUPPORTED One or more of the control options are not\r
641 supported in the implementation.\r
642 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
643 @retval Others Failed to create the HTTP_IO or configure it.\r
644\r
645**/\r
646EFI_STATUS\r
647HttpIoCreateIo (\r
648 IN EFI_HANDLE Image,\r
649 IN EFI_HANDLE Controller,\r
650 IN UINT8 IpVersion,\r
651 IN HTTP_IO_CONFIG_DATA *ConfigData,\r
652 OUT HTTP_IO *HttpIo\r
653 )\r
654{\r
655 EFI_STATUS Status;\r
656 EFI_HTTP_CONFIG_DATA HttpConfigData;\r
657 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;\r
b659408b 658 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;\r
d933e70a
JW
659 EFI_HTTP_PROTOCOL *Http;\r
660 EFI_EVENT Event;\r
661 \r
662 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {\r
663 return EFI_INVALID_PARAMETER;\r
664 }\r
665\r
666 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {\r
667 return EFI_UNSUPPORTED;\r
668 }\r
669\r
670 ZeroMem (HttpIo, sizeof (HTTP_IO));\r
671 \r
672 //\r
673 // Create the HTTP child instance and get the HTTP protocol.\r
674 // \r
675 Status = NetLibCreateServiceChild (\r
676 Controller,\r
677 Image,\r
678 &gEfiHttpServiceBindingProtocolGuid,\r
679 &HttpIo->Handle\r
680 );\r
681 if (EFI_ERROR (Status)) {\r
682 return Status;\r
683 }\r
684\r
685 Status = gBS->OpenProtocol (\r
686 HttpIo->Handle,\r
687 &gEfiHttpProtocolGuid,\r
688 (VOID **) &Http,\r
689 Image,\r
690 Controller,\r
691 EFI_OPEN_PROTOCOL_BY_DRIVER\r
692 );\r
693 if (EFI_ERROR (Status) || (Http == NULL)) {\r
694 goto ON_ERROR;\r
695 }\r
696\r
697 //\r
698 // Init the configuration data and configure the HTTP child.\r
699 //\r
700 HttpIo->Image = Image;\r
701 HttpIo->Controller = Controller;\r
702 HttpIo->IpVersion = IpVersion;\r
703 HttpIo->Http = Http;\r
704\r
705 ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));\r
706 HttpConfigData.HttpVersion = HttpVersion11;\r
707 HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;\r
708 if (HttpIo->IpVersion == IP_VERSION_4) {\r
709 HttpConfigData.LocalAddressIsIPv6 = FALSE;\r
710 \r
711 Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;\r
712 Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;\r
713 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);\r
714 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
715 HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; \r
716 } else {\r
b659408b
ZL
717 HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
718 Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;\r
719 IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
720 HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
d933e70a
JW
721 }\r
722 \r
723 Status = Http->Configure (Http, &HttpConfigData);\r
724 if (EFI_ERROR (Status)) {\r
725 goto ON_ERROR;\r
726 }\r
727\r
728 //\r
729 // Create events for variuos asynchronous operations.\r
730 //\r
731 Status = gBS->CreateEvent (\r
732 EVT_NOTIFY_SIGNAL,\r
733 TPL_NOTIFY,\r
b659408b 734 HttpBootCommonNotify,\r
d933e70a
JW
735 &HttpIo->IsTxDone,\r
736 &Event\r
737 );\r
738 if (EFI_ERROR (Status)) {\r
739 goto ON_ERROR;\r
740 }\r
741 HttpIo->ReqToken.Event = Event;\r
742 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;\r
743\r
744 Status = gBS->CreateEvent (\r
745 EVT_NOTIFY_SIGNAL,\r
746 TPL_NOTIFY,\r
b659408b 747 HttpBootCommonNotify,\r
d933e70a
JW
748 &HttpIo->IsRxDone,\r
749 &Event\r
750 );\r
751 if (EFI_ERROR (Status)) {\r
752 goto ON_ERROR;\r
753 }\r
754 HttpIo->RspToken.Event = Event;\r
755 HttpIo->RspToken.Message = &HttpIo->RspMessage;\r
756\r
757 return EFI_SUCCESS;\r
758 \r
759ON_ERROR:\r
760 HttpIoDestroyIo (HttpIo);\r
761\r
762 return Status;\r
763}\r
764\r
765/**\r
766 Destroy the HTTP_IO and release the resouces. \r
767\r
768 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.\r
769\r
770**/\r
771VOID\r
772HttpIoDestroyIo (\r
773 IN HTTP_IO *HttpIo\r
774 )\r
775{\r
776 EFI_HTTP_PROTOCOL *Http;\r
777 EFI_EVENT Event;\r
778\r
779 if (HttpIo == NULL) {\r
780 return;\r
781 }\r
782\r
783 Event = HttpIo->ReqToken.Event;\r
784 if (Event != NULL) {\r
785 gBS->CloseEvent (Event);\r
786 }\r
787\r
788 Event = HttpIo->RspToken.Event;\r
789 if (Event != NULL) {\r
790 gBS->CloseEvent (Event);\r
791 }\r
792 \r
793 Http = HttpIo->Http;\r
794 if (Http != NULL) {\r
795 Http->Configure (Http, NULL);\r
796 gBS->CloseProtocol (\r
797 HttpIo->Handle,\r
798 &gEfiHttpProtocolGuid,\r
799 HttpIo->Image,\r
800 HttpIo->Controller\r
801 );\r
802 }\r
803\r
804 NetLibDestroyServiceChild (\r
805 HttpIo->Controller,\r
806 HttpIo->Image,\r
807 &gEfiHttpServiceBindingProtocolGuid,\r
808 HttpIo->Handle\r
809 );\r
810}\r
811\r
812/**\r
813 Synchronously send a HTTP REQUEST message to the server.\r
814 \r
815 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
816 @param[in] Request A pointer to storage such data as URL and HTTP method.\r
817 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
818 @param[in] Headers Array containing list of HTTP headers.\r
819 @param[in] BodyLength Length in bytes of the HTTP body.\r
820 @param[in] Body Body associated with the HTTP request. \r
821 \r
822 @retval EFI_SUCCESS The HTTP request is trasmitted.\r
823 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
824 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
825 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
826 @retval Others Other errors as indicated.\r
827\r
828**/\r
829EFI_STATUS\r
830HttpIoSendRequest (\r
831 IN HTTP_IO *HttpIo,\r
832 IN EFI_HTTP_REQUEST_DATA *Request,\r
833 IN UINTN HeaderCount,\r
834 IN EFI_HTTP_HEADER *Headers,\r
835 IN UINTN BodyLength,\r
836 IN VOID *Body\r
837 )\r
838{\r
839 EFI_STATUS Status;\r
840 EFI_HTTP_PROTOCOL *Http;\r
841\r
842 if (HttpIo == NULL || HttpIo->Http == NULL) {\r
843 return EFI_INVALID_PARAMETER;\r
844 }\r
845\r
846 HttpIo->ReqToken.Status = EFI_NOT_READY;\r
847 HttpIo->ReqToken.Message->Data.Request = Request;\r
848 HttpIo->ReqToken.Message->HeaderCount = HeaderCount;\r
849 HttpIo->ReqToken.Message->Headers = Headers;\r
850 HttpIo->ReqToken.Message->BodyLength = BodyLength;\r
851 HttpIo->ReqToken.Message->Body = Body;\r
852\r
853 //\r
854 // Queue the request token to HTTP instances.\r
855 //\r
856 Http = HttpIo->Http;\r
857 HttpIo->IsTxDone = FALSE;\r
858 Status = Http->Request (\r
859 Http,\r
860 &HttpIo->ReqToken\r
861 );\r
862 if (EFI_ERROR (Status)) {\r
863 return Status;\r
864 }\r
865\r
866 //\r
867 // Poll the network until transmit finish.\r
868 //\r
869 while (!HttpIo->IsTxDone) {\r
870 Http->Poll (Http);\r
871 }\r
872\r
873 return HttpIo->ReqToken.Status;\r
874}\r
875\r
876/**\r
877 Synchronously receive a HTTP RESPONSE message from the server.\r
878 \r
879 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
880 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).\r
881 FALSE to continue receive the previous response message.\r
882 @param[out] ResponseData Point to a wrapper of the received response data.\r
883 \r
ef422fc5 884 @retval EFI_SUCCESS The HTTP response is received.\r
d933e70a
JW
885 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
886 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
887 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
888 @retval Others Other errors as indicated.\r
889\r
890**/\r
891EFI_STATUS\r
892HttpIoRecvResponse (\r
893 IN HTTP_IO *HttpIo,\r
894 IN BOOLEAN RecvMsgHeader,\r
ef422fc5 895 OUT HTTP_IO_RESPONSE_DATA *ResponseData\r
d933e70a
JW
896 )\r
897{\r
898 EFI_STATUS Status;\r
899 EFI_HTTP_PROTOCOL *Http;\r
900\r
901 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {\r
902 return EFI_INVALID_PARAMETER;\r
903 }\r
904\r
905 //\r
906 // Queue the response token to HTTP instances.\r
907 //\r
908 HttpIo->RspToken.Status = EFI_NOT_READY;\r
909 if (RecvMsgHeader) {\r
910 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;\r
911 } else {\r
912 HttpIo->RspToken.Message->Data.Response = NULL;\r
913 }\r
914 HttpIo->RspToken.Message->HeaderCount = 0;\r
915 HttpIo->RspToken.Message->Headers = NULL;\r
916 HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;\r
917 HttpIo->RspToken.Message->Body = ResponseData->Body;\r
918\r
919 Http = HttpIo->Http;\r
920 HttpIo->IsRxDone = FALSE;\r
921 Status = Http->Response (\r
922 Http,\r
923 &HttpIo->RspToken\r
924 );\r
925 \r
926 if (EFI_ERROR (Status)) {\r
927 return Status;\r
928 }\r
929\r
930 //\r
62cae351 931 // Poll the network until receive finish.\r
d933e70a
JW
932 //\r
933 while (!HttpIo->IsRxDone) {\r
934 Http->Poll (Http);\r
935 }\r
936\r
937 //\r
938 // Store the received data into the wrapper.\r
939 //\r
072289f4
ZL
940 ResponseData->Status = HttpIo->RspToken.Status;\r
941 ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
942 ResponseData->Headers = HttpIo->RspToken.Message->Headers;\r
943 ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;\r
d933e70a
JW
944\r
945 return Status;\r
946}\r
fa848a40
FS
947\r
948/**\r
949 Get the URI address string from the input device path.\r
950\r
951 Caller need to free the buffer in the UriAddress pointer.\r
952 \r
953 @param[in] FilePath Pointer to the device path which contains a URI device path node.\r
954 @param[in] UriAddress The URI address string extract from the device path.\r
955 \r
956 @retval EFI_SUCCESS The URI string is returned.\r
957 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
958\r
959**/\r
960EFI_STATUS\r
961HttpBootParseFilePath (\r
962 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
963 OUT CHAR8 **UriAddress\r
964 )\r
965{\r
966 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
967 URI_DEVICE_PATH *UriDevicePath;\r
968 CHAR8 *Uri;\r
969 UINTN UriStrLength;\r
970\r
971 if (FilePath == NULL) {\r
972 return EFI_INVALID_PARAMETER;\r
973 }\r
974\r
975 *UriAddress = NULL;\r
976\r
977 //\r
978 // Extract the URI address from the FilePath\r
979 //\r
980 TempDevicePath = FilePath;\r
981 while (!IsDevicePathEnd (TempDevicePath)) {\r
982 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
983 (DevicePathSubType (TempDevicePath) == MSG_URI_DP)) {\r
984 UriDevicePath = (URI_DEVICE_PATH*) TempDevicePath;\r
985 //\r
986 // UEFI Spec doesn't require the URI to be a NULL-terminated string\r
987 // So we allocate a new buffer and always append a '\0' to it.\r
988 //\r
989 UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
990 if (UriStrLength == 0) {\r
991 //\r
992 // return a NULL UriAddress if it's a empty URI device path node.\r
993 //\r
994 break;\r
995 }\r
996 Uri = AllocatePool (UriStrLength + 1);\r
997 if (Uri == NULL) {\r
998 return EFI_OUT_OF_RESOURCES;\r
999 }\r
1000 CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL));\r
1001 Uri[DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL)] = '\0';\r
1002\r
1003 *UriAddress = Uri;\r
1004 }\r
1005 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1006 }\r
1007\r
1008 return EFI_SUCCESS;\r
1009}\r