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