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