]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
Add error handling for TPM in S3 resume failure.
[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
4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials are licensed and made available under \r
6the terms and conditions of the BSD License that accompanies this distribution. \r
7The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php. \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "HttpBootDxe.h"\r
16\r
17\r
18/**\r
19 Get the Nic handle using any child handle in the IPv4 stack.\r
20\r
21 @param[in] ControllerHandle Pointer to child handle over IPv4.\r
22\r
23 @return NicHandle The pointer to the Nic handle.\r
24 @return NULL Can't find the Nic handle.\r
25\r
26**/\r
27EFI_HANDLE\r
28HttpBootGetNicByIp4Children (\r
29 IN EFI_HANDLE ControllerHandle\r
30 )\r
31{\r
32 EFI_HANDLE NicHandle;\r
33\r
34 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
35 if (NicHandle == NULL) {\r
36 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);\r
37 if (NicHandle == NULL) {\r
38 return NULL;\r
39 }\r
40 }\r
41\r
42 return NicHandle;\r
43}\r
44\r
b659408b
ZL
45/**\r
46 Get the Nic handle using any child handle in the IPv6 stack.\r
47\r
48 @param[in] ControllerHandle Pointer to child handle over IPv6.\r
49\r
50 @return NicHandle The pointer to the Nic handle.\r
51 @return NULL Can't find the Nic handle.\r
52\r
53**/\r
54EFI_HANDLE\r
55HttpBootGetNicByIp6Children (\r
56 IN EFI_HANDLE ControllerHandle\r
57 )\r
58{\r
59 EFI_HANDLE NicHandle;\r
60 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);\r
61 if (NicHandle == NULL) {\r
62 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);\r
63 if (NicHandle == NULL) {\r
64 return NULL;\r
65 }\r
66 }\r
67\r
68 return NicHandle;\r
69}\r
d933e70a
JW
70\r
71/**\r
72 This function is to convert UINTN to ASCII string with the required formatting.\r
73\r
74 @param[in] Number Numeric value to be converted.\r
75 @param[in] Buffer The pointer to the buffer for ASCII string.\r
76 @param[in] Length The length of the required format.\r
77\r
78**/\r
79VOID\r
80HttpBootUintnToAscDecWithFormat (\r
81 IN UINTN Number,\r
82 IN UINT8 *Buffer,\r
83 IN INTN Length\r
84 )\r
85{\r
86 UINTN Remainder;\r
87\r
88 while (Length > 0) {\r
89 Length--;\r
90 Remainder = Number % 10;\r
91 Number /= 10;\r
92 Buffer[Length] = (UINT8) ('0' + Remainder);\r
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
149/**\r
150 Notify the callback function when an event is triggered.\r
151\r
152 @param[in] Event The triggered event.\r
153 @param[in] Context The opaque parameter to the function.\r
154\r
155**/\r
156VOID\r
157EFIAPI\r
158HttpBootCommonNotify (\r
159 IN EFI_EVENT Event,\r
160 IN VOID *Context\r
161 )\r
162{\r
163 *((BOOLEAN *) Context) = TRUE;\r
164}\r
165\r
166/**\r
167 Retrieve the host address using the EFI_DNS6_PROTOCOL.\r
168\r
169 @param[in] Private The pointer to the driver's private data.\r
170 @param[in] HostName Pointer to buffer containing hostname.\r
171 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
172\r
173 @retval EFI_SUCCESS Operation succeeded.\r
174 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
175 @retval Others Other errors as indicated. \r
176**/\r
177EFI_STATUS\r
178HttpBootDns (\r
179 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
180 IN CHAR16 *HostName,\r
181 OUT EFI_IPv6_ADDRESS *IpAddress \r
182 )\r
183{\r
184 EFI_STATUS Status;\r
185 EFI_DNS6_PROTOCOL *Dns6;\r
186 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
187 EFI_DNS6_COMPLETION_TOKEN Token;\r
188 EFI_HANDLE Dns6Handle;\r
189 EFI_IP6_CONFIG_PROTOCOL *Ip6Config;\r
190 EFI_IPv6_ADDRESS *DnsServerList;\r
191 UINTN DnsServerListCount;\r
192 UINTN DataSize;\r
193 BOOLEAN IsDone; \r
194 \r
195 DnsServerList = NULL;\r
196 DnsServerListCount = 0;\r
197 Dns6 = NULL;\r
198 Dns6Handle = NULL;\r
199 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
200 \r
201 //\r
202 // Get DNS server list from EFI IPv6 Configuration protocol.\r
203 //\r
204 Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);\r
205 if (!EFI_ERROR (Status)) {\r
206 //\r
207 // Get the required size.\r
208 //\r
209 DataSize = 0;\r
210 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);\r
211 if (Status == EFI_BUFFER_TOO_SMALL) {\r
212 DnsServerList = AllocatePool (DataSize);\r
213 if (DnsServerList == NULL) {\r
214 return EFI_OUT_OF_RESOURCES;\r
215 } \r
216\r
217 Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);\r
218 if (EFI_ERROR (Status)) {\r
219 FreePool (DnsServerList);\r
220 DnsServerList = NULL;\r
221 } else {\r
222 DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);\r
223 }\r
224 }\r
225 }\r
226 //\r
227 // Create a DNSv6 child instance and get the protocol.\r
228 //\r
229 Status = NetLibCreateServiceChild (\r
230 Private->Controller,\r
231 Private->Image,\r
232 &gEfiDns6ServiceBindingProtocolGuid,\r
233 &Dns6Handle\r
234 );\r
235 if (EFI_ERROR (Status)) {\r
236 goto Exit;\r
237 } \r
238 \r
239 Status = gBS->OpenProtocol (\r
240 Dns6Handle,\r
241 &gEfiDns6ProtocolGuid,\r
242 (VOID **) &Dns6,\r
243 Private->Image,\r
244 Private->Controller,\r
245 EFI_OPEN_PROTOCOL_BY_DRIVER\r
246 );\r
247 if (EFI_ERROR (Status)) {\r
248 goto Exit;\r
249 }\r
250\r
251 //\r
252 // Configure DNS6 instance for the DNS server address and protocol.\r
253 //\r
254 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
255 Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;\r
256 Dns6ConfigData.DnsServerList = DnsServerList;\r
257 Dns6ConfigData.EnableDnsCache = TRUE;\r
258 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
259 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6);\r
260 Status = Dns6->Configure (\r
261 Dns6,\r
262 &Dns6ConfigData\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 goto Exit;\r
266 }\r
267 \r
268 Token.Status = EFI_NOT_READY;\r
269 IsDone = FALSE;\r
270 //\r
271 // Create event to set the IsDone flag when name resolution is finished.\r
272 //\r
273 Status = gBS->CreateEvent (\r
274 EVT_NOTIFY_SIGNAL,\r
275 TPL_NOTIFY,\r
276 HttpBootCommonNotify,\r
277 &IsDone,\r
278 &Token.Event\r
279 );\r
280 if (EFI_ERROR (Status)) {\r
281 goto Exit;\r
282 }\r
283\r
284 //\r
285 // Start asynchronous name resolution.\r
286 //\r
287 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
288 if (EFI_ERROR (Status)) {\r
289 goto Exit;\r
290 }\r
291\r
292 while (!IsDone) {\r
293 Dns6->Poll (Dns6);\r
294 }\r
295 \r
296 //\r
297 // Name resolution is done, check result.\r
298 //\r
299 Status = Token.Status; \r
300 if (!EFI_ERROR (Status)) {\r
301 if (Token.RspData.H2AData == NULL) {\r
302 Status = EFI_DEVICE_ERROR;\r
303 goto Exit;\r
304 }\r
305 if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {\r
306 Status = EFI_DEVICE_ERROR;\r
307 goto Exit;\r
308 }\r
309 //\r
310 // We just return the first IPv6 address from DNS protocol.\r
311 //\r
312 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
313 Status = EFI_SUCCESS;\r
314 }\r
315Exit:\r
316\r
317 if (Token.Event != NULL) {\r
318 gBS->CloseEvent (Token.Event);\r
319 }\r
320 if (Token.RspData.H2AData != NULL) {\r
321 if (Token.RspData.H2AData->IpList != NULL) {\r
322 FreePool (Token.RspData.H2AData->IpList);\r
323 }\r
324 FreePool (Token.RspData.H2AData);\r
325 }\r
326\r
327 if (Dns6 != NULL) {\r
328 Dns6->Configure (Dns6, NULL);\r
329 \r
330 gBS->CloseProtocol (\r
331 Dns6Handle,\r
332 &gEfiDns6ProtocolGuid,\r
333 Private->Image,\r
334 Private->Controller\r
335 );\r
336 }\r
337\r
338 if (Dns6Handle != NULL) {\r
339 NetLibDestroyServiceChild (\r
340 Private->Controller,\r
341 Private->Image,\r
342 &gEfiDns6ServiceBindingProtocolGuid,\r
343 Dns6Handle\r
344 );\r
345 }\r
346\r
347 if (DnsServerList != NULL) {\r
348 FreePool (DnsServerList);\r
349 }\r
350 \r
351 return Status; \r
352}\r
d933e70a
JW
353/**\r
354 Create a HTTP_IO_HEADER to hold the HTTP header items.\r
355\r
356 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.\r
357\r
358 @return A pointer of the HTTP header holder or NULL if failed.\r
359 \r
360**/\r
361HTTP_IO_HEADER *\r
362HttpBootCreateHeader (\r
363 UINTN MaxHeaderCount\r
b659408b 364 )\r
d933e70a
JW
365{\r
366 HTTP_IO_HEADER *HttpIoHeader;\r
367\r
368 if (MaxHeaderCount == 0) {\r
369 return NULL;\r
370 }\r
371\r
372 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));\r
373 if (HttpIoHeader == NULL) {\r
374 return NULL;\r
375 }\r
376\r
377 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;\r
378 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);\r
379\r
380 return HttpIoHeader;\r
381}\r
382\r
383/**\r
384 Destroy the HTTP_IO_HEADER and release the resouces. \r
385\r
386 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.\r
387\r
388**/\r
389VOID\r
390HttpBootFreeHeader (\r
391 IN HTTP_IO_HEADER *HttpIoHeader\r
392 )\r
393{\r
394 UINTN Index;\r
395 \r
396 if (HttpIoHeader != NULL) {\r
397 if (HttpIoHeader->HeaderCount != 0) {\r
398 for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {\r
399 FreePool (HttpIoHeader->Headers[Index].FieldName);\r
400 FreePool (HttpIoHeader->Headers[Index].FieldValue);\r
401 }\r
402 }\r
403 FreePool (HttpIoHeader);\r
404 }\r
405}\r
406\r
407/**\r
408 Find a specified header field according to the field name.\r
409\r
410 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
411 @param[in] Headers Array containing list of HTTP headers.\r
412 @param[in] FieldName Null terminated string which describes a field name. \r
413\r
414 @return Pointer to the found header or NULL.\r
415\r
416**/\r
417EFI_HTTP_HEADER *\r
418HttpBootFindHeader (\r
419 IN UINTN HeaderCount,\r
420 IN EFI_HTTP_HEADER *Headers,\r
421 IN CHAR8 *FieldName\r
422 )\r
423{\r
424 UINTN Index;\r
425 \r
426 if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {\r
427 return NULL;\r
428 }\r
429\r
430 for (Index = 0; Index < HeaderCount; Index++){\r
431 //\r
432 // Field names are case-insensitive (RFC 2616).\r
433 //\r
434 if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {\r
435 return &Headers[Index];\r
436 }\r
437 }\r
438 return NULL;\r
439}\r
440\r
441/**\r
442 Set or update a HTTP header with the field name and corresponding value.\r
443\r
444 @param[in] HttpIoHeader Point to the HTTP header holder.\r
445 @param[in] FieldName Null terminated string which describes a field name. \r
446 @param[in] FieldValue Null terminated string which describes the corresponding field value.\r
447\r
448 @retval EFI_SUCCESS The HTTP header has been set or updated.\r
449 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
450 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.\r
451 @retval Other Unexpected error happened.\r
452 \r
453**/\r
454EFI_STATUS\r
455HttpBootSetHeader (\r
456 IN HTTP_IO_HEADER *HttpIoHeader,\r
457 IN CHAR8 *FieldName,\r
458 IN CHAR8 *FieldValue\r
459 )\r
460{\r
461 EFI_HTTP_HEADER *Header;\r
462 UINTN StrSize;\r
463 CHAR8 *NewFieldValue;\r
464 \r
465 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {\r
466 return EFI_INVALID_PARAMETER;\r
467 }\r
468\r
469 Header = HttpBootFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);\r
470 if (Header == NULL) {\r
471 //\r
472 // Add a new header.\r
473 //\r
474 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {\r
475 return EFI_OUT_OF_RESOURCES;\r
476 }\r
477 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];\r
478\r
479 StrSize = AsciiStrSize (FieldName);\r
480 Header->FieldName = AllocatePool (StrSize);\r
481 if (Header->FieldName == NULL) {\r
482 return EFI_OUT_OF_RESOURCES;\r
483 }\r
484 CopyMem (Header->FieldName, FieldName, StrSize);\r
485 Header->FieldName[StrSize -1] = '\0';\r
486\r
487 StrSize = AsciiStrSize (FieldValue);\r
488 Header->FieldValue = AllocatePool (StrSize);\r
489 if (Header->FieldValue == NULL) {\r
490 FreePool (Header->FieldName);\r
491 return EFI_OUT_OF_RESOURCES;\r
492 }\r
493 CopyMem (Header->FieldValue, FieldValue, StrSize);\r
494 Header->FieldValue[StrSize -1] = '\0';\r
495\r
496 HttpIoHeader->HeaderCount++;\r
497 } else {\r
498 //\r
499 // Update an existing one.\r
500 //\r
501 StrSize = AsciiStrSize (FieldValue);\r
502 NewFieldValue = AllocatePool (StrSize);\r
503 if (NewFieldValue == NULL) {\r
504 return EFI_OUT_OF_RESOURCES;\r
505 }\r
506 CopyMem (NewFieldValue, FieldValue, StrSize);\r
507 NewFieldValue[StrSize -1] = '\0';\r
508 \r
509 if (Header->FieldValue != NULL) {\r
510 FreePool (Header->FieldValue);\r
511 }\r
512 Header->FieldValue = NewFieldValue;\r
513 }\r
514\r
515 return EFI_SUCCESS;\r
516}\r
517\r
d933e70a
JW
518/**\r
519 Create a HTTP_IO to access the HTTP service. It will create and configure\r
520 a HTTP child handle.\r
521\r
522 @param[in] Image The handle of the driver image.\r
523 @param[in] Controller The handle of the controller.\r
524 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
525 @param[in] ConfigData The HTTP_IO configuration data.\r
526 @param[out] HttpIo The HTTP_IO.\r
527 \r
528 @retval EFI_SUCCESS The HTTP_IO is created and configured.\r
529 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
530 @retval EFI_UNSUPPORTED One or more of the control options are not\r
531 supported in the implementation.\r
532 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
533 @retval Others Failed to create the HTTP_IO or configure it.\r
534\r
535**/\r
536EFI_STATUS\r
537HttpIoCreateIo (\r
538 IN EFI_HANDLE Image,\r
539 IN EFI_HANDLE Controller,\r
540 IN UINT8 IpVersion,\r
541 IN HTTP_IO_CONFIG_DATA *ConfigData,\r
542 OUT HTTP_IO *HttpIo\r
543 )\r
544{\r
545 EFI_STATUS Status;\r
546 EFI_HTTP_CONFIG_DATA HttpConfigData;\r
547 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;\r
b659408b 548 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;\r
d933e70a
JW
549 EFI_HTTP_PROTOCOL *Http;\r
550 EFI_EVENT Event;\r
551 \r
552 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {\r
553 return EFI_INVALID_PARAMETER;\r
554 }\r
555\r
556 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {\r
557 return EFI_UNSUPPORTED;\r
558 }\r
559\r
560 ZeroMem (HttpIo, sizeof (HTTP_IO));\r
561 \r
562 //\r
563 // Create the HTTP child instance and get the HTTP protocol.\r
564 // \r
565 Status = NetLibCreateServiceChild (\r
566 Controller,\r
567 Image,\r
568 &gEfiHttpServiceBindingProtocolGuid,\r
569 &HttpIo->Handle\r
570 );\r
571 if (EFI_ERROR (Status)) {\r
572 return Status;\r
573 }\r
574\r
575 Status = gBS->OpenProtocol (\r
576 HttpIo->Handle,\r
577 &gEfiHttpProtocolGuid,\r
578 (VOID **) &Http,\r
579 Image,\r
580 Controller,\r
581 EFI_OPEN_PROTOCOL_BY_DRIVER\r
582 );\r
583 if (EFI_ERROR (Status) || (Http == NULL)) {\r
584 goto ON_ERROR;\r
585 }\r
586\r
587 //\r
588 // Init the configuration data and configure the HTTP child.\r
589 //\r
590 HttpIo->Image = Image;\r
591 HttpIo->Controller = Controller;\r
592 HttpIo->IpVersion = IpVersion;\r
593 HttpIo->Http = Http;\r
594\r
595 ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));\r
596 HttpConfigData.HttpVersion = HttpVersion11;\r
597 HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;\r
598 if (HttpIo->IpVersion == IP_VERSION_4) {\r
599 HttpConfigData.LocalAddressIsIPv6 = FALSE;\r
600 \r
601 Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;\r
602 Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;\r
603 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);\r
604 IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);\r
605 HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; \r
606 } else {\r
b659408b
ZL
607 HttpConfigData.LocalAddressIsIPv6 = TRUE;\r
608 Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;\r
609 IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);\r
610 HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;\r
d933e70a
JW
611 }\r
612 \r
613 Status = Http->Configure (Http, &HttpConfigData);\r
614 if (EFI_ERROR (Status)) {\r
615 goto ON_ERROR;\r
616 }\r
617\r
618 //\r
619 // Create events for variuos asynchronous operations.\r
620 //\r
621 Status = gBS->CreateEvent (\r
622 EVT_NOTIFY_SIGNAL,\r
623 TPL_NOTIFY,\r
b659408b 624 HttpBootCommonNotify,\r
d933e70a
JW
625 &HttpIo->IsTxDone,\r
626 &Event\r
627 );\r
628 if (EFI_ERROR (Status)) {\r
629 goto ON_ERROR;\r
630 }\r
631 HttpIo->ReqToken.Event = Event;\r
632 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;\r
633\r
634 Status = gBS->CreateEvent (\r
635 EVT_NOTIFY_SIGNAL,\r
636 TPL_NOTIFY,\r
b659408b 637 HttpBootCommonNotify,\r
d933e70a
JW
638 &HttpIo->IsRxDone,\r
639 &Event\r
640 );\r
641 if (EFI_ERROR (Status)) {\r
642 goto ON_ERROR;\r
643 }\r
644 HttpIo->RspToken.Event = Event;\r
645 HttpIo->RspToken.Message = &HttpIo->RspMessage;\r
646\r
647 return EFI_SUCCESS;\r
648 \r
649ON_ERROR:\r
650 HttpIoDestroyIo (HttpIo);\r
651\r
652 return Status;\r
653}\r
654\r
655/**\r
656 Destroy the HTTP_IO and release the resouces. \r
657\r
658 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.\r
659\r
660**/\r
661VOID\r
662HttpIoDestroyIo (\r
663 IN HTTP_IO *HttpIo\r
664 )\r
665{\r
666 EFI_HTTP_PROTOCOL *Http;\r
667 EFI_EVENT Event;\r
668\r
669 if (HttpIo == NULL) {\r
670 return;\r
671 }\r
672\r
673 Event = HttpIo->ReqToken.Event;\r
674 if (Event != NULL) {\r
675 gBS->CloseEvent (Event);\r
676 }\r
677\r
678 Event = HttpIo->RspToken.Event;\r
679 if (Event != NULL) {\r
680 gBS->CloseEvent (Event);\r
681 }\r
682 \r
683 Http = HttpIo->Http;\r
684 if (Http != NULL) {\r
685 Http->Configure (Http, NULL);\r
686 gBS->CloseProtocol (\r
687 HttpIo->Handle,\r
688 &gEfiHttpProtocolGuid,\r
689 HttpIo->Image,\r
690 HttpIo->Controller\r
691 );\r
692 }\r
693\r
694 NetLibDestroyServiceChild (\r
695 HttpIo->Controller,\r
696 HttpIo->Image,\r
697 &gEfiHttpServiceBindingProtocolGuid,\r
698 HttpIo->Handle\r
699 );\r
700}\r
701\r
702/**\r
703 Synchronously send a HTTP REQUEST message to the server.\r
704 \r
705 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
706 @param[in] Request A pointer to storage such data as URL and HTTP method.\r
707 @param[in] HeaderCount Number of HTTP header structures in Headers list. \r
708 @param[in] Headers Array containing list of HTTP headers.\r
709 @param[in] BodyLength Length in bytes of the HTTP body.\r
710 @param[in] Body Body associated with the HTTP request. \r
711 \r
712 @retval EFI_SUCCESS The HTTP request is trasmitted.\r
713 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
714 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
715 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
716 @retval Others Other errors as indicated.\r
717\r
718**/\r
719EFI_STATUS\r
720HttpIoSendRequest (\r
721 IN HTTP_IO *HttpIo,\r
722 IN EFI_HTTP_REQUEST_DATA *Request,\r
723 IN UINTN HeaderCount,\r
724 IN EFI_HTTP_HEADER *Headers,\r
725 IN UINTN BodyLength,\r
726 IN VOID *Body\r
727 )\r
728{\r
729 EFI_STATUS Status;\r
730 EFI_HTTP_PROTOCOL *Http;\r
731\r
732 if (HttpIo == NULL || HttpIo->Http == NULL) {\r
733 return EFI_INVALID_PARAMETER;\r
734 }\r
735\r
736 HttpIo->ReqToken.Status = EFI_NOT_READY;\r
737 HttpIo->ReqToken.Message->Data.Request = Request;\r
738 HttpIo->ReqToken.Message->HeaderCount = HeaderCount;\r
739 HttpIo->ReqToken.Message->Headers = Headers;\r
740 HttpIo->ReqToken.Message->BodyLength = BodyLength;\r
741 HttpIo->ReqToken.Message->Body = Body;\r
742\r
743 //\r
744 // Queue the request token to HTTP instances.\r
745 //\r
746 Http = HttpIo->Http;\r
747 HttpIo->IsTxDone = FALSE;\r
748 Status = Http->Request (\r
749 Http,\r
750 &HttpIo->ReqToken\r
751 );\r
752 if (EFI_ERROR (Status)) {\r
753 return Status;\r
754 }\r
755\r
756 //\r
757 // Poll the network until transmit finish.\r
758 //\r
759 while (!HttpIo->IsTxDone) {\r
760 Http->Poll (Http);\r
761 }\r
762\r
763 return HttpIo->ReqToken.Status;\r
764}\r
765\r
766/**\r
767 Synchronously receive a HTTP RESPONSE message from the server.\r
768 \r
769 @param[in] HttpIo The HttpIo wrapping the HTTP service.\r
770 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).\r
771 FALSE to continue receive the previous response message.\r
772 @param[out] ResponseData Point to a wrapper of the received response data.\r
773 \r
774 @retval EFI_SUCCESS The HTTP resopnse is received.\r
775 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
776 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
777 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
778 @retval Others Other errors as indicated.\r
779\r
780**/\r
781EFI_STATUS\r
782HttpIoRecvResponse (\r
783 IN HTTP_IO *HttpIo,\r
784 IN BOOLEAN RecvMsgHeader,\r
785 OUT HTTP_IO_RESOPNSE_DATA *ResponseData\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
789 EFI_HTTP_PROTOCOL *Http;\r
790\r
791 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {\r
792 return EFI_INVALID_PARAMETER;\r
793 }\r
794\r
795 //\r
796 // Queue the response token to HTTP instances.\r
797 //\r
798 HttpIo->RspToken.Status = EFI_NOT_READY;\r
799 if (RecvMsgHeader) {\r
800 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;\r
801 } else {\r
802 HttpIo->RspToken.Message->Data.Response = NULL;\r
803 }\r
804 HttpIo->RspToken.Message->HeaderCount = 0;\r
805 HttpIo->RspToken.Message->Headers = NULL;\r
806 HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;\r
807 HttpIo->RspToken.Message->Body = ResponseData->Body;\r
808\r
809 Http = HttpIo->Http;\r
810 HttpIo->IsRxDone = FALSE;\r
811 Status = Http->Response (\r
812 Http,\r
813 &HttpIo->RspToken\r
814 );\r
815 \r
816 if (EFI_ERROR (Status)) {\r
817 return Status;\r
818 }\r
819\r
820 //\r
821 // Poll the network until transmit finish.\r
822 //\r
823 while (!HttpIo->IsRxDone) {\r
824 Http->Poll (Http);\r
825 }\r
826\r
827 //\r
828 // Store the received data into the wrapper.\r
829 //\r
b659408b 830 Status = HttpIo->RspToken.Status;\r
d933e70a
JW
831 if (!EFI_ERROR (Status)) {\r
832 ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;\r
833 ResponseData->Headers = HttpIo->RspToken.Message->Headers;\r
834 ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;\r
835 }\r
836\r
837 return Status;\r
838}\r