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