HttpBootSupport.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. /** @file
  2. Support functions implementation for UEFI HTTP boot driver.
  3. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
  4. (C) Copyright 2016 - 2020 Hewlett Packard Enterprise Development LP<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "HttpBootDxe.h"
  8. /**
  9. Get the Nic handle using any child handle in the IPv4 stack.
  10. @param[in] ControllerHandle Pointer to child handle over IPv4.
  11. @return NicHandle The pointer to the Nic handle.
  12. @return NULL Can't find the Nic handle.
  13. **/
  14. EFI_HANDLE
  15. HttpBootGetNicByIp4Children (
  16. IN EFI_HANDLE ControllerHandle
  17. )
  18. {
  19. EFI_HANDLE NicHandle;
  20. NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);
  21. if (NicHandle == NULL) {
  22. NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
  23. if (NicHandle == NULL) {
  24. return NULL;
  25. }
  26. }
  27. return NicHandle;
  28. }
  29. /**
  30. Get the Nic handle using any child handle in the IPv6 stack.
  31. @param[in] ControllerHandle Pointer to child handle over IPv6.
  32. @return NicHandle The pointer to the Nic handle.
  33. @return NULL Can't find the Nic handle.
  34. **/
  35. EFI_HANDLE
  36. HttpBootGetNicByIp6Children (
  37. IN EFI_HANDLE ControllerHandle
  38. )
  39. {
  40. EFI_HANDLE NicHandle;
  41. NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);
  42. if (NicHandle == NULL) {
  43. NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
  44. if (NicHandle == NULL) {
  45. return NULL;
  46. }
  47. }
  48. return NicHandle;
  49. }
  50. /**
  51. This function is to convert UINTN to ASCII string with the required formatting.
  52. @param[in] Number Numeric value to be converted.
  53. @param[in] Buffer The pointer to the buffer for ASCII string.
  54. @param[in] Length The length of the required format.
  55. **/
  56. VOID
  57. HttpBootUintnToAscDecWithFormat (
  58. IN UINTN Number,
  59. IN UINT8 *Buffer,
  60. IN INTN Length
  61. )
  62. {
  63. UINTN Remainder;
  64. for ( ; Length > 0; Length--) {
  65. Remainder = Number % 10;
  66. Number /= 10;
  67. Buffer[Length - 1] = (UINT8)('0' + Remainder);
  68. }
  69. }
  70. /**
  71. This function is to display the IPv4 address.
  72. @param[in] Ip The pointer to the IPv4 address.
  73. **/
  74. VOID
  75. HttpBootShowIp4Addr (
  76. IN EFI_IPv4_ADDRESS *Ip
  77. )
  78. {
  79. UINTN Index;
  80. for (Index = 0; Index < 4; Index++) {
  81. AsciiPrint ("%d", Ip->Addr[Index]);
  82. if (Index < 3) {
  83. AsciiPrint (".");
  84. }
  85. }
  86. }
  87. /**
  88. This function is to display the IPv6 address.
  89. @param[in] Ip The pointer to the IPv6 address.
  90. **/
  91. VOID
  92. HttpBootShowIp6Addr (
  93. IN EFI_IPv6_ADDRESS *Ip
  94. )
  95. {
  96. UINTN Index;
  97. for (Index = 0; Index < 16; Index++) {
  98. if (Ip->Addr[Index] != 0) {
  99. AsciiPrint ("%x", Ip->Addr[Index]);
  100. }
  101. Index++;
  102. if (Index > 15) {
  103. return;
  104. }
  105. if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
  106. AsciiPrint ("0");
  107. }
  108. AsciiPrint ("%x", Ip->Addr[Index]);
  109. if (Index < 15) {
  110. AsciiPrint (":");
  111. }
  112. }
  113. }
  114. /**
  115. This function is to display the HTTP error status.
  116. @param[in] StatusCode The status code value in HTTP message.
  117. **/
  118. VOID
  119. HttpBootPrintErrorMessage (
  120. EFI_HTTP_STATUS_CODE StatusCode
  121. )
  122. {
  123. AsciiPrint ("\n");
  124. switch (StatusCode) {
  125. case HTTP_STATUS_300_MULTIPLE_CHOICES:
  126. AsciiPrint ("\n Redirection: 300 Multiple Choices");
  127. break;
  128. case HTTP_STATUS_301_MOVED_PERMANENTLY:
  129. AsciiPrint ("\n Redirection: 301 Moved Permanently");
  130. break;
  131. case HTTP_STATUS_302_FOUND:
  132. AsciiPrint ("\n Redirection: 302 Found");
  133. break;
  134. case HTTP_STATUS_303_SEE_OTHER:
  135. AsciiPrint ("\n Redirection: 303 See Other");
  136. break;
  137. case HTTP_STATUS_304_NOT_MODIFIED:
  138. AsciiPrint ("\n Redirection: 304 Not Modified");
  139. break;
  140. case HTTP_STATUS_305_USE_PROXY:
  141. AsciiPrint ("\n Redirection: 305 Use Proxy");
  142. break;
  143. case HTTP_STATUS_307_TEMPORARY_REDIRECT:
  144. AsciiPrint ("\n Redirection: 307 Temporary Redirect");
  145. break;
  146. case HTTP_STATUS_308_PERMANENT_REDIRECT:
  147. AsciiPrint ("\n Redirection: 308 Permanent Redirect");
  148. break;
  149. case HTTP_STATUS_400_BAD_REQUEST:
  150. AsciiPrint ("\n Client Error: 400 Bad Request");
  151. break;
  152. case HTTP_STATUS_401_UNAUTHORIZED:
  153. AsciiPrint ("\n Client Error: 401 Unauthorized");
  154. break;
  155. case HTTP_STATUS_402_PAYMENT_REQUIRED:
  156. AsciiPrint ("\n Client Error: 402 Payment Required");
  157. break;
  158. case HTTP_STATUS_403_FORBIDDEN:
  159. AsciiPrint ("\n Client Error: 403 Forbidden");
  160. break;
  161. case HTTP_STATUS_404_NOT_FOUND:
  162. AsciiPrint ("\n Client Error: 404 Not Found");
  163. break;
  164. case HTTP_STATUS_405_METHOD_NOT_ALLOWED:
  165. AsciiPrint ("\n Client Error: 405 Method Not Allowed");
  166. break;
  167. case HTTP_STATUS_406_NOT_ACCEPTABLE:
  168. AsciiPrint ("\n Client Error: 406 Not Acceptable");
  169. break;
  170. case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:
  171. AsciiPrint ("\n Client Error: 407 Proxy Authentication Required");
  172. break;
  173. case HTTP_STATUS_408_REQUEST_TIME_OUT:
  174. AsciiPrint ("\n Client Error: 408 Request Timeout");
  175. break;
  176. case HTTP_STATUS_409_CONFLICT:
  177. AsciiPrint ("\n Client Error: 409 Conflict");
  178. break;
  179. case HTTP_STATUS_410_GONE:
  180. AsciiPrint ("\n Client Error: 410 Gone");
  181. break;
  182. case HTTP_STATUS_411_LENGTH_REQUIRED:
  183. AsciiPrint ("\n Client Error: 411 Length Required");
  184. break;
  185. case HTTP_STATUS_412_PRECONDITION_FAILED:
  186. AsciiPrint ("\n Client Error: 412 Precondition Failed");
  187. break;
  188. case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:
  189. AsciiPrint ("\n Client Error: 413 Request Entity Too Large");
  190. break;
  191. case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:
  192. AsciiPrint ("\n Client Error: 414 Request URI Too Long");
  193. break;
  194. case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:
  195. AsciiPrint ("\n Client Error: 415 Unsupported Media Type");
  196. break;
  197. case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:
  198. AsciiPrint ("\n Client Error: 416 Requested Range Not Satisfiable");
  199. break;
  200. case HTTP_STATUS_417_EXPECTATION_FAILED:
  201. AsciiPrint ("\n Client Error: 417 Expectation Failed");
  202. break;
  203. case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:
  204. AsciiPrint ("\n Server Error: 500 Internal Server Error");
  205. break;
  206. case HTTP_STATUS_501_NOT_IMPLEMENTED:
  207. AsciiPrint ("\n Server Error: 501 Not Implemented");
  208. break;
  209. case HTTP_STATUS_502_BAD_GATEWAY:
  210. AsciiPrint ("\n Server Error: 502 Bad Gateway");
  211. break;
  212. case HTTP_STATUS_503_SERVICE_UNAVAILABLE:
  213. AsciiPrint ("\n Server Error: 503 Service Unavailable");
  214. break;
  215. case HTTP_STATUS_504_GATEWAY_TIME_OUT:
  216. AsciiPrint ("\n Server Error: 504 Gateway Timeout");
  217. break;
  218. case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:
  219. AsciiPrint ("\n Server Error: 505 HTTP Version Not Supported");
  220. break;
  221. default:;
  222. }
  223. }
  224. /**
  225. Notify the callback function when an event is triggered.
  226. @param[in] Event The triggered event.
  227. @param[in] Context The opaque parameter to the function.
  228. **/
  229. VOID
  230. EFIAPI
  231. HttpBootCommonNotify (
  232. IN EFI_EVENT Event,
  233. IN VOID *Context
  234. )
  235. {
  236. *((BOOLEAN *)Context) = TRUE;
  237. }
  238. /**
  239. Retrieve the host address using the EFI_DNS6_PROTOCOL.
  240. @param[in] Private The pointer to the driver's private data.
  241. @param[in] HostName Pointer to buffer containing hostname.
  242. @param[out] IpAddress On output, pointer to buffer containing IPv6 address.
  243. @retval EFI_SUCCESS Operation succeeded.
  244. @retval EFI_DEVICE_ERROR An unexpected network error occurred.
  245. @retval Others Other errors as indicated.
  246. **/
  247. EFI_STATUS
  248. HttpBootDns (
  249. IN HTTP_BOOT_PRIVATE_DATA *Private,
  250. IN CHAR16 *HostName,
  251. OUT EFI_IPv6_ADDRESS *IpAddress
  252. )
  253. {
  254. EFI_STATUS Status;
  255. EFI_DNS6_PROTOCOL *Dns6;
  256. EFI_DNS6_CONFIG_DATA Dns6ConfigData;
  257. EFI_DNS6_COMPLETION_TOKEN Token;
  258. EFI_HANDLE Dns6Handle;
  259. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  260. EFI_IPv6_ADDRESS *DnsServerList;
  261. UINTN DnsServerListCount;
  262. UINTN DataSize;
  263. BOOLEAN IsDone;
  264. DnsServerList = NULL;
  265. DnsServerListCount = 0;
  266. Dns6 = NULL;
  267. Dns6Handle = NULL;
  268. ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));
  269. //
  270. // Get DNS server list from EFI IPv6 Configuration protocol.
  271. //
  272. Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **)&Ip6Config);
  273. if (!EFI_ERROR (Status)) {
  274. //
  275. // Get the required size.
  276. //
  277. DataSize = 0;
  278. Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);
  279. if (Status == EFI_BUFFER_TOO_SMALL) {
  280. DnsServerList = AllocatePool (DataSize);
  281. if (DnsServerList == NULL) {
  282. return EFI_OUT_OF_RESOURCES;
  283. }
  284. Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);
  285. if (EFI_ERROR (Status)) {
  286. FreePool (DnsServerList);
  287. DnsServerList = NULL;
  288. } else {
  289. DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
  290. }
  291. }
  292. }
  293. //
  294. // Create a DNSv6 child instance and get the protocol.
  295. //
  296. Status = NetLibCreateServiceChild (
  297. Private->Controller,
  298. Private->Ip6Nic->ImageHandle,
  299. &gEfiDns6ServiceBindingProtocolGuid,
  300. &Dns6Handle
  301. );
  302. if (EFI_ERROR (Status)) {
  303. goto Exit;
  304. }
  305. Status = gBS->OpenProtocol (
  306. Dns6Handle,
  307. &gEfiDns6ProtocolGuid,
  308. (VOID **)&Dns6,
  309. Private->Ip6Nic->ImageHandle,
  310. Private->Controller,
  311. EFI_OPEN_PROTOCOL_BY_DRIVER
  312. );
  313. if (EFI_ERROR (Status)) {
  314. goto Exit;
  315. }
  316. //
  317. // Configure DNS6 instance for the DNS server address and protocol.
  318. //
  319. ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));
  320. Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;
  321. Dns6ConfigData.DnsServerList = DnsServerList;
  322. Dns6ConfigData.EnableDnsCache = TRUE;
  323. Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;
  324. IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->StationIp.v6);
  325. Status = Dns6->Configure (
  326. Dns6,
  327. &Dns6ConfigData
  328. );
  329. if (EFI_ERROR (Status)) {
  330. goto Exit;
  331. }
  332. Token.Status = EFI_NOT_READY;
  333. IsDone = FALSE;
  334. //
  335. // Create event to set the IsDone flag when name resolution is finished.
  336. //
  337. Status = gBS->CreateEvent (
  338. EVT_NOTIFY_SIGNAL,
  339. TPL_NOTIFY,
  340. HttpBootCommonNotify,
  341. &IsDone,
  342. &Token.Event
  343. );
  344. if (EFI_ERROR (Status)) {
  345. goto Exit;
  346. }
  347. //
  348. // Start asynchronous name resolution.
  349. //
  350. Status = Dns6->HostNameToIp (Dns6, HostName, &Token);
  351. if (EFI_ERROR (Status)) {
  352. goto Exit;
  353. }
  354. while (!IsDone) {
  355. Dns6->Poll (Dns6);
  356. }
  357. //
  358. // Name resolution is done, check result.
  359. //
  360. Status = Token.Status;
  361. if (!EFI_ERROR (Status)) {
  362. if (Token.RspData.H2AData == NULL) {
  363. Status = EFI_DEVICE_ERROR;
  364. goto Exit;
  365. }
  366. if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) {
  367. Status = EFI_DEVICE_ERROR;
  368. goto Exit;
  369. }
  370. //
  371. // We just return the first IPv6 address from DNS protocol.
  372. //
  373. IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);
  374. Status = EFI_SUCCESS;
  375. }
  376. Exit:
  377. if (Token.Event != NULL) {
  378. gBS->CloseEvent (Token.Event);
  379. }
  380. if (Token.RspData.H2AData != NULL) {
  381. if (Token.RspData.H2AData->IpList != NULL) {
  382. FreePool (Token.RspData.H2AData->IpList);
  383. }
  384. FreePool (Token.RspData.H2AData);
  385. }
  386. if (Dns6 != NULL) {
  387. Dns6->Configure (Dns6, NULL);
  388. gBS->CloseProtocol (
  389. Dns6Handle,
  390. &gEfiDns6ProtocolGuid,
  391. Private->Ip6Nic->ImageHandle,
  392. Private->Controller
  393. );
  394. }
  395. if (Dns6Handle != NULL) {
  396. NetLibDestroyServiceChild (
  397. Private->Controller,
  398. Private->Ip6Nic->ImageHandle,
  399. &gEfiDns6ServiceBindingProtocolGuid,
  400. Dns6Handle
  401. );
  402. }
  403. if (DnsServerList != NULL) {
  404. FreePool (DnsServerList);
  405. }
  406. return Status;
  407. }
  408. /**
  409. This function checks the HTTP(S) URI scheme.
  410. @param[in] Uri The pointer to the URI string.
  411. @retval EFI_SUCCESS The URI scheme is valid.
  412. @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.
  413. @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.
  414. **/
  415. EFI_STATUS
  416. HttpBootCheckUriScheme (
  417. IN CHAR8 *Uri
  418. )
  419. {
  420. UINTN Index;
  421. EFI_STATUS Status;
  422. Status = EFI_SUCCESS;
  423. //
  424. // Convert the scheme to all lower case.
  425. //
  426. for (Index = 0; Index < AsciiStrLen (Uri); Index++) {
  427. if (Uri[Index] == ':') {
  428. break;
  429. }
  430. if ((Uri[Index] >= 'A') && (Uri[Index] <= 'Z')) {
  431. Uri[Index] -= (CHAR8)('A' - 'a');
  432. }
  433. }
  434. //
  435. // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.
  436. //
  437. if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {
  438. DEBUG ((DEBUG_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));
  439. return EFI_INVALID_PARAMETER;
  440. }
  441. //
  442. // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.
  443. //
  444. if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {
  445. DEBUG ((DEBUG_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));
  446. return EFI_ACCESS_DENIED;
  447. }
  448. return Status;
  449. }
  450. /**
  451. Get the URI address string from the input device path.
  452. Caller need to free the buffer in the UriAddress pointer.
  453. @param[in] FilePath Pointer to the device path which contains a URI device path node.
  454. @param[out] UriAddress The URI address string extract from the device path.
  455. @retval EFI_SUCCESS The URI string is returned.
  456. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  457. **/
  458. EFI_STATUS
  459. HttpBootParseFilePath (
  460. IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
  461. OUT CHAR8 **UriAddress
  462. )
  463. {
  464. EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
  465. URI_DEVICE_PATH *UriDevicePath;
  466. CHAR8 *Uri;
  467. UINTN UriStrLength;
  468. if (FilePath == NULL) {
  469. return EFI_INVALID_PARAMETER;
  470. }
  471. *UriAddress = NULL;
  472. //
  473. // Extract the URI address from the FilePath
  474. //
  475. TempDevicePath = FilePath;
  476. while (!IsDevicePathEnd (TempDevicePath)) {
  477. if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
  478. (DevicePathSubType (TempDevicePath) == MSG_URI_DP))
  479. {
  480. UriDevicePath = (URI_DEVICE_PATH *)TempDevicePath;
  481. //
  482. // UEFI Spec doesn't require the URI to be a NULL-terminated string
  483. // So we allocate a new buffer and always append a '\0' to it.
  484. //
  485. UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
  486. if (UriStrLength == 0) {
  487. //
  488. // return a NULL UriAddress if it's a empty URI device path node.
  489. //
  490. break;
  491. }
  492. Uri = AllocatePool (UriStrLength + 1);
  493. if (Uri == NULL) {
  494. return EFI_OUT_OF_RESOURCES;
  495. }
  496. CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL));
  497. Uri[DevicePathNodeLength (UriDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL)] = '\0';
  498. *UriAddress = Uri;
  499. }
  500. TempDevicePath = NextDevicePathNode (TempDevicePath);
  501. }
  502. return EFI_SUCCESS;
  503. }
  504. /**
  505. This function returns the image type according to server replied HTTP message
  506. and also the image's URI info.
  507. @param[in] Uri The pointer to the image's URI string.
  508. @param[in] UriParser URI Parse result returned by NetHttpParseUrl().
  509. @param[in] HeaderCount Number of HTTP header structures in Headers list.
  510. @param[in] Headers Array containing list of HTTP headers.
  511. @param[out] ImageType The image type of the downloaded file.
  512. @retval EFI_SUCCESS The image type is returned in ImageType.
  513. @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.
  514. @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.
  515. @retval EFI_NOT_FOUND Failed to identify the image type.
  516. @retval Others Unexpected error happened.
  517. **/
  518. EFI_STATUS
  519. HttpBootCheckImageType (
  520. IN CHAR8 *Uri,
  521. IN VOID *UriParser,
  522. IN UINTN HeaderCount,
  523. IN EFI_HTTP_HEADER *Headers,
  524. OUT HTTP_BOOT_IMAGE_TYPE *ImageType
  525. )
  526. {
  527. EFI_STATUS Status;
  528. EFI_HTTP_HEADER *Header;
  529. CHAR8 *FilePath;
  530. CHAR8 *FilePost;
  531. if ((Uri == NULL) || (UriParser == NULL) || (ImageType == NULL)) {
  532. return EFI_INVALID_PARAMETER;
  533. }
  534. if ((HeaderCount != 0) && (Headers == NULL)) {
  535. return EFI_INVALID_PARAMETER;
  536. }
  537. //
  538. // Determine the image type by the HTTP Content-Type header field first.
  539. // "application/efi" -> EFI Image
  540. // "application/vnd.efi-iso" -> CD/DVD Image
  541. // "application/vnd.efi-img" -> Virtual Disk Image
  542. //
  543. Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);
  544. if (Header != NULL) {
  545. if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {
  546. *ImageType = ImageTypeEfi;
  547. return EFI_SUCCESS;
  548. } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {
  549. *ImageType = ImageTypeVirtualCd;
  550. return EFI_SUCCESS;
  551. } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {
  552. *ImageType = ImageTypeVirtualDisk;
  553. return EFI_SUCCESS;
  554. }
  555. }
  556. //
  557. // Determine the image type by file extension:
  558. // *.efi -> EFI Image
  559. // *.iso -> CD/DVD Image
  560. // *.img -> Virtual Disk Image
  561. //
  562. Status = HttpUrlGetPath (
  563. Uri,
  564. UriParser,
  565. &FilePath
  566. );
  567. if (EFI_ERROR (Status)) {
  568. return Status;
  569. }
  570. FilePost = FilePath + AsciiStrLen (FilePath) - 4;
  571. if (AsciiStriCmp (FilePost, ".efi") == 0) {
  572. *ImageType = ImageTypeEfi;
  573. } else if (AsciiStriCmp (FilePost, ".iso") == 0) {
  574. *ImageType = ImageTypeVirtualCd;
  575. } else if (AsciiStriCmp (FilePost, ".img") == 0) {
  576. *ImageType = ImageTypeVirtualDisk;
  577. } else {
  578. *ImageType = ImageTypeMax;
  579. }
  580. FreePool (FilePath);
  581. return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;
  582. }
  583. /**
  584. This function register the RAM disk info to the system.
  585. @param[in] Private The pointer to the driver's private data.
  586. @param[in] BufferSize The size of Buffer in bytes.
  587. @param[in] Buffer The base address of the RAM disk.
  588. @param[in] ImageType The image type of the file in Buffer.
  589. @retval EFI_SUCCESS The RAM disk has been registered.
  590. @retval EFI_NOT_FOUND No RAM disk protocol instances were found.
  591. @retval EFI_UNSUPPORTED The ImageType is not supported.
  592. @retval Others Unexpected error happened.
  593. **/
  594. EFI_STATUS
  595. HttpBootRegisterRamDisk (
  596. IN HTTP_BOOT_PRIVATE_DATA *Private,
  597. IN UINTN BufferSize,
  598. IN VOID *Buffer,
  599. IN HTTP_BOOT_IMAGE_TYPE ImageType
  600. )
  601. {
  602. EFI_RAM_DISK_PROTOCOL *RamDisk;
  603. EFI_STATUS Status;
  604. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  605. EFI_GUID *RamDiskType;
  606. ASSERT (Private != NULL);
  607. ASSERT (Buffer != NULL);
  608. ASSERT (BufferSize != 0);
  609. Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID **)&RamDisk);
  610. if (EFI_ERROR (Status)) {
  611. DEBUG ((DEBUG_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));
  612. return Status;
  613. }
  614. if (ImageType == ImageTypeVirtualCd) {
  615. RamDiskType = &gEfiVirtualCdGuid;
  616. } else if (ImageType == ImageTypeVirtualDisk) {
  617. RamDiskType = &gEfiVirtualDiskGuid;
  618. } else {
  619. return EFI_UNSUPPORTED;
  620. }
  621. Status = RamDisk->Register (
  622. (UINTN)Buffer,
  623. (UINT64)BufferSize,
  624. RamDiskType,
  625. Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,
  626. &DevicePath
  627. );
  628. if (EFI_ERROR (Status)) {
  629. DEBUG ((DEBUG_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));
  630. }
  631. return Status;
  632. }
  633. /**
  634. Indicate if the HTTP status code indicates a redirection.
  635. @param[in] StatusCode HTTP status code from server.
  636. @return TRUE if it's redirection.
  637. **/
  638. BOOLEAN
  639. HttpBootIsHttpRedirectStatusCode (
  640. IN EFI_HTTP_STATUS_CODE StatusCode
  641. )
  642. {
  643. if ((StatusCode == HTTP_STATUS_301_MOVED_PERMANENTLY) ||
  644. (StatusCode == HTTP_STATUS_302_FOUND) ||
  645. (StatusCode == HTTP_STATUS_307_TEMPORARY_REDIRECT) ||
  646. (StatusCode == HTTP_STATUS_308_PERMANENT_REDIRECT))
  647. {
  648. return TRUE;
  649. }
  650. return FALSE;
  651. }