HttpBootSupport.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338
  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 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. Create a HTTP_IO_HEADER to hold the HTTP header items.
  410. @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.
  411. @return A pointer of the HTTP header holder or NULL if failed.
  412. **/
  413. HTTP_IO_HEADER *
  414. HttpBootCreateHeader (
  415. UINTN MaxHeaderCount
  416. )
  417. {
  418. HTTP_IO_HEADER *HttpIoHeader;
  419. if (MaxHeaderCount == 0) {
  420. return NULL;
  421. }
  422. HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));
  423. if (HttpIoHeader == NULL) {
  424. return NULL;
  425. }
  426. HttpIoHeader->MaxHeaderCount = MaxHeaderCount;
  427. HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);
  428. return HttpIoHeader;
  429. }
  430. /**
  431. Destroy the HTTP_IO_HEADER and release the resouces.
  432. @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.
  433. **/
  434. VOID
  435. HttpBootFreeHeader (
  436. IN HTTP_IO_HEADER *HttpIoHeader
  437. )
  438. {
  439. UINTN Index;
  440. if (HttpIoHeader != NULL) {
  441. if (HttpIoHeader->HeaderCount != 0) {
  442. for (Index = 0; Index < HttpIoHeader->HeaderCount; Index++) {
  443. FreePool (HttpIoHeader->Headers[Index].FieldName);
  444. FreePool (HttpIoHeader->Headers[Index].FieldValue);
  445. }
  446. }
  447. FreePool (HttpIoHeader);
  448. }
  449. }
  450. /**
  451. Set or update a HTTP header with the field name and corresponding value.
  452. @param[in] HttpIoHeader Point to the HTTP header holder.
  453. @param[in] FieldName Null terminated string which describes a field name.
  454. @param[in] FieldValue Null terminated string which describes the corresponding field value.
  455. @retval EFI_SUCCESS The HTTP header has been set or updated.
  456. @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
  457. @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.
  458. @retval Other Unexpected error happened.
  459. **/
  460. EFI_STATUS
  461. HttpBootSetHeader (
  462. IN HTTP_IO_HEADER *HttpIoHeader,
  463. IN CHAR8 *FieldName,
  464. IN CHAR8 *FieldValue
  465. )
  466. {
  467. EFI_HTTP_HEADER *Header;
  468. UINTN StrSize;
  469. CHAR8 *NewFieldValue;
  470. if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {
  471. return EFI_INVALID_PARAMETER;
  472. }
  473. Header = HttpFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);
  474. if (Header == NULL) {
  475. //
  476. // Add a new header.
  477. //
  478. if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {
  479. return EFI_OUT_OF_RESOURCES;
  480. }
  481. Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];
  482. StrSize = AsciiStrSize (FieldName);
  483. Header->FieldName = AllocatePool (StrSize);
  484. if (Header->FieldName == NULL) {
  485. return EFI_OUT_OF_RESOURCES;
  486. }
  487. CopyMem (Header->FieldName, FieldName, StrSize);
  488. Header->FieldName[StrSize -1] = '\0';
  489. StrSize = AsciiStrSize (FieldValue);
  490. Header->FieldValue = AllocatePool (StrSize);
  491. if (Header->FieldValue == NULL) {
  492. FreePool (Header->FieldName);
  493. return EFI_OUT_OF_RESOURCES;
  494. }
  495. CopyMem (Header->FieldValue, FieldValue, StrSize);
  496. Header->FieldValue[StrSize -1] = '\0';
  497. HttpIoHeader->HeaderCount++;
  498. } else {
  499. //
  500. // Update an existing one.
  501. //
  502. StrSize = AsciiStrSize (FieldValue);
  503. NewFieldValue = AllocatePool (StrSize);
  504. if (NewFieldValue == NULL) {
  505. return EFI_OUT_OF_RESOURCES;
  506. }
  507. CopyMem (NewFieldValue, FieldValue, StrSize);
  508. NewFieldValue[StrSize -1] = '\0';
  509. if (Header->FieldValue != NULL) {
  510. FreePool (Header->FieldValue);
  511. }
  512. Header->FieldValue = NewFieldValue;
  513. }
  514. return EFI_SUCCESS;
  515. }
  516. /**
  517. Notify the callback function when an event is triggered.
  518. @param[in] Context The opaque parameter to the function.
  519. **/
  520. VOID
  521. EFIAPI
  522. HttpIoNotifyDpc (
  523. IN VOID *Context
  524. )
  525. {
  526. *((BOOLEAN *) Context) = TRUE;
  527. }
  528. /**
  529. Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.
  530. @param[in] Event The event signaled.
  531. @param[in] Context The opaque parameter to the function.
  532. **/
  533. VOID
  534. EFIAPI
  535. HttpIoNotify (
  536. IN EFI_EVENT Event,
  537. IN VOID *Context
  538. )
  539. {
  540. //
  541. // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK
  542. //
  543. QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context);
  544. }
  545. /**
  546. Create a HTTP_IO to access the HTTP service. It will create and configure
  547. a HTTP child handle.
  548. @param[in] Image The handle of the driver image.
  549. @param[in] Controller The handle of the controller.
  550. @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
  551. @param[in] ConfigData The HTTP_IO configuration data.
  552. @param[in] Callback Callback function which will be invoked when specified
  553. HTTP_IO_CALLBACK_EVENT happened.
  554. @param[in] Context The Context data which will be passed to the Callback function.
  555. @param[out] HttpIo The HTTP_IO.
  556. @retval EFI_SUCCESS The HTTP_IO is created and configured.
  557. @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  558. @retval EFI_UNSUPPORTED One or more of the control options are not
  559. supported in the implementation.
  560. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  561. @retval Others Failed to create the HTTP_IO or configure it.
  562. **/
  563. EFI_STATUS
  564. HttpIoCreateIo (
  565. IN EFI_HANDLE Image,
  566. IN EFI_HANDLE Controller,
  567. IN UINT8 IpVersion,
  568. IN HTTP_IO_CONFIG_DATA *ConfigData,
  569. IN HTTP_IO_CALLBACK Callback,
  570. IN VOID *Context,
  571. OUT HTTP_IO *HttpIo
  572. )
  573. {
  574. EFI_STATUS Status;
  575. EFI_HTTP_CONFIG_DATA HttpConfigData;
  576. EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;
  577. EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;
  578. EFI_HTTP_PROTOCOL *Http;
  579. EFI_EVENT Event;
  580. if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {
  581. return EFI_INVALID_PARAMETER;
  582. }
  583. if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {
  584. return EFI_UNSUPPORTED;
  585. }
  586. ZeroMem (HttpIo, sizeof (HTTP_IO));
  587. //
  588. // Create the HTTP child instance and get the HTTP protocol.
  589. //
  590. Status = NetLibCreateServiceChild (
  591. Controller,
  592. Image,
  593. &gEfiHttpServiceBindingProtocolGuid,
  594. &HttpIo->Handle
  595. );
  596. if (EFI_ERROR (Status)) {
  597. return Status;
  598. }
  599. Status = gBS->OpenProtocol (
  600. HttpIo->Handle,
  601. &gEfiHttpProtocolGuid,
  602. (VOID **) &Http,
  603. Image,
  604. Controller,
  605. EFI_OPEN_PROTOCOL_BY_DRIVER
  606. );
  607. if (EFI_ERROR (Status) || (Http == NULL)) {
  608. goto ON_ERROR;
  609. }
  610. //
  611. // Init the configuration data and configure the HTTP child.
  612. //
  613. HttpIo->Image = Image;
  614. HttpIo->Controller = Controller;
  615. HttpIo->IpVersion = IpVersion;
  616. HttpIo->Http = Http;
  617. HttpIo->Callback = Callback;
  618. HttpIo->Context = Context;
  619. ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA));
  620. HttpConfigData.HttpVersion = HttpVersion11;
  621. HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut;
  622. if (HttpIo->IpVersion == IP_VERSION_4) {
  623. HttpConfigData.LocalAddressIsIPv6 = FALSE;
  624. Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress;
  625. Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort;
  626. IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp);
  627. IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask);
  628. HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint;
  629. } else {
  630. HttpConfigData.LocalAddressIsIPv6 = TRUE;
  631. Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort;
  632. IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp);
  633. HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;
  634. }
  635. Status = Http->Configure (Http, &HttpConfigData);
  636. if (EFI_ERROR (Status)) {
  637. goto ON_ERROR;
  638. }
  639. //
  640. // Create events for variuos asynchronous operations.
  641. //
  642. Status = gBS->CreateEvent (
  643. EVT_NOTIFY_SIGNAL,
  644. TPL_NOTIFY,
  645. HttpIoNotify,
  646. &HttpIo->IsTxDone,
  647. &Event
  648. );
  649. if (EFI_ERROR (Status)) {
  650. goto ON_ERROR;
  651. }
  652. HttpIo->ReqToken.Event = Event;
  653. HttpIo->ReqToken.Message = &HttpIo->ReqMessage;
  654. Status = gBS->CreateEvent (
  655. EVT_NOTIFY_SIGNAL,
  656. TPL_NOTIFY,
  657. HttpIoNotify,
  658. &HttpIo->IsRxDone,
  659. &Event
  660. );
  661. if (EFI_ERROR (Status)) {
  662. goto ON_ERROR;
  663. }
  664. HttpIo->RspToken.Event = Event;
  665. HttpIo->RspToken.Message = &HttpIo->RspMessage;
  666. //
  667. // Create TimeoutEvent for response
  668. //
  669. Status = gBS->CreateEvent (
  670. EVT_TIMER,
  671. TPL_CALLBACK,
  672. NULL,
  673. NULL,
  674. &Event
  675. );
  676. if (EFI_ERROR (Status)) {
  677. goto ON_ERROR;
  678. }
  679. HttpIo->TimeoutEvent = Event;
  680. return EFI_SUCCESS;
  681. ON_ERROR:
  682. HttpIoDestroyIo (HttpIo);
  683. return Status;
  684. }
  685. /**
  686. Destroy the HTTP_IO and release the resouces.
  687. @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
  688. **/
  689. VOID
  690. HttpIoDestroyIo (
  691. IN HTTP_IO *HttpIo
  692. )
  693. {
  694. EFI_HTTP_PROTOCOL *Http;
  695. EFI_EVENT Event;
  696. if (HttpIo == NULL) {
  697. return;
  698. }
  699. Event = HttpIo->ReqToken.Event;
  700. if (Event != NULL) {
  701. gBS->CloseEvent (Event);
  702. }
  703. Event = HttpIo->RspToken.Event;
  704. if (Event != NULL) {
  705. gBS->CloseEvent (Event);
  706. }
  707. Event = HttpIo->TimeoutEvent;
  708. if (Event != NULL) {
  709. gBS->CloseEvent (Event);
  710. }
  711. Http = HttpIo->Http;
  712. if (Http != NULL) {
  713. Http->Configure (Http, NULL);
  714. gBS->CloseProtocol (
  715. HttpIo->Handle,
  716. &gEfiHttpProtocolGuid,
  717. HttpIo->Image,
  718. HttpIo->Controller
  719. );
  720. }
  721. NetLibDestroyServiceChild (
  722. HttpIo->Controller,
  723. HttpIo->Image,
  724. &gEfiHttpServiceBindingProtocolGuid,
  725. HttpIo->Handle
  726. );
  727. }
  728. /**
  729. Synchronously send a HTTP REQUEST message to the server.
  730. @param[in] HttpIo The HttpIo wrapping the HTTP service.
  731. @param[in] Request A pointer to storage such data as URL and HTTP method.
  732. @param[in] HeaderCount Number of HTTP header structures in Headers list.
  733. @param[in] Headers Array containing list of HTTP headers.
  734. @param[in] BodyLength Length in bytes of the HTTP body.
  735. @param[in] Body Body associated with the HTTP request.
  736. @retval EFI_SUCCESS The HTTP request is trasmitted.
  737. @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  738. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  739. @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
  740. @retval Others Other errors as indicated.
  741. **/
  742. EFI_STATUS
  743. HttpIoSendRequest (
  744. IN HTTP_IO *HttpIo,
  745. IN EFI_HTTP_REQUEST_DATA *Request,
  746. IN UINTN HeaderCount,
  747. IN EFI_HTTP_HEADER *Headers,
  748. IN UINTN BodyLength,
  749. IN VOID *Body
  750. )
  751. {
  752. EFI_STATUS Status;
  753. EFI_HTTP_PROTOCOL *Http;
  754. if (HttpIo == NULL || HttpIo->Http == NULL) {
  755. return EFI_INVALID_PARAMETER;
  756. }
  757. HttpIo->ReqToken.Status = EFI_NOT_READY;
  758. HttpIo->ReqToken.Message->Data.Request = Request;
  759. HttpIo->ReqToken.Message->HeaderCount = HeaderCount;
  760. HttpIo->ReqToken.Message->Headers = Headers;
  761. HttpIo->ReqToken.Message->BodyLength = BodyLength;
  762. HttpIo->ReqToken.Message->Body = Body;
  763. if (HttpIo->Callback != NULL) {
  764. Status = HttpIo->Callback (
  765. HttpIoRequest,
  766. HttpIo->ReqToken.Message,
  767. HttpIo->Context
  768. );
  769. if (EFI_ERROR (Status)) {
  770. return Status;
  771. }
  772. }
  773. //
  774. // Queue the request token to HTTP instances.
  775. //
  776. Http = HttpIo->Http;
  777. HttpIo->IsTxDone = FALSE;
  778. Status = Http->Request (
  779. Http,
  780. &HttpIo->ReqToken
  781. );
  782. if (EFI_ERROR (Status)) {
  783. return Status;
  784. }
  785. //
  786. // Poll the network until transmit finish.
  787. //
  788. while (!HttpIo->IsTxDone) {
  789. Http->Poll (Http);
  790. }
  791. return HttpIo->ReqToken.Status;
  792. }
  793. /**
  794. Synchronously receive a HTTP RESPONSE message from the server.
  795. @param[in] HttpIo The HttpIo wrapping the HTTP service.
  796. @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
  797. FALSE to continue receive the previous response message.
  798. @param[out] ResponseData Point to a wrapper of the received response data.
  799. @retval EFI_SUCCESS The HTTP response is received.
  800. @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  801. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  802. @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
  803. @retval Others Other errors as indicated.
  804. **/
  805. EFI_STATUS
  806. HttpIoRecvResponse (
  807. IN HTTP_IO *HttpIo,
  808. IN BOOLEAN RecvMsgHeader,
  809. OUT HTTP_IO_RESPONSE_DATA *ResponseData
  810. )
  811. {
  812. EFI_STATUS Status;
  813. EFI_HTTP_PROTOCOL *Http;
  814. if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {
  815. return EFI_INVALID_PARAMETER;
  816. }
  817. //
  818. // Start the timer, and wait Timeout seconds to receive the header packet.
  819. //
  820. Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative, HTTP_BOOT_RESPONSE_TIMEOUT * TICKS_PER_MS);
  821. if (EFI_ERROR (Status)) {
  822. return Status;
  823. }
  824. //
  825. // Queue the response token to HTTP instances.
  826. //
  827. HttpIo->RspToken.Status = EFI_NOT_READY;
  828. if (RecvMsgHeader) {
  829. HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;
  830. } else {
  831. HttpIo->RspToken.Message->Data.Response = NULL;
  832. }
  833. HttpIo->RspToken.Message->HeaderCount = 0;
  834. HttpIo->RspToken.Message->Headers = NULL;
  835. HttpIo->RspToken.Message->BodyLength = ResponseData->BodyLength;
  836. HttpIo->RspToken.Message->Body = ResponseData->Body;
  837. Http = HttpIo->Http;
  838. HttpIo->IsRxDone = FALSE;
  839. Status = Http->Response (
  840. Http,
  841. &HttpIo->RspToken
  842. );
  843. if (EFI_ERROR (Status)) {
  844. gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);
  845. return Status;
  846. }
  847. //
  848. // Poll the network until receive finish.
  849. //
  850. while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL) || EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) {
  851. Http->Poll (Http);
  852. }
  853. gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);
  854. if (!HttpIo->IsRxDone) {
  855. //
  856. // Timeout occurs, cancel the response token.
  857. //
  858. Http->Cancel (Http, &HttpIo->RspToken);
  859. Status = EFI_TIMEOUT;
  860. return Status;
  861. } else {
  862. HttpIo->IsRxDone = FALSE;
  863. }
  864. if ((HttpIo->Callback != NULL) &&
  865. (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo->RspToken.Status == EFI_HTTP_ERROR)) {
  866. Status = HttpIo->Callback (
  867. HttpIoResponse,
  868. HttpIo->RspToken.Message,
  869. HttpIo->Context
  870. );
  871. if (EFI_ERROR (Status)) {
  872. return Status;
  873. }
  874. }
  875. //
  876. // Store the received data into the wrapper.
  877. //
  878. ResponseData->Status = HttpIo->RspToken.Status;
  879. ResponseData->HeaderCount = HttpIo->RspToken.Message->HeaderCount;
  880. ResponseData->Headers = HttpIo->RspToken.Message->Headers;
  881. ResponseData->BodyLength = HttpIo->RspToken.Message->BodyLength;
  882. return Status;
  883. }
  884. /**
  885. This function checks the HTTP(S) URI scheme.
  886. @param[in] Uri The pointer to the URI string.
  887. @retval EFI_SUCCESS The URI scheme is valid.
  888. @retval EFI_INVALID_PARAMETER The URI scheme is not HTTP or HTTPS.
  889. @retval EFI_ACCESS_DENIED HTTP is disabled and the URI is HTTP.
  890. **/
  891. EFI_STATUS
  892. HttpBootCheckUriScheme (
  893. IN CHAR8 *Uri
  894. )
  895. {
  896. UINTN Index;
  897. EFI_STATUS Status;
  898. Status = EFI_SUCCESS;
  899. //
  900. // Convert the scheme to all lower case.
  901. //
  902. for (Index = 0; Index < AsciiStrLen (Uri); Index++) {
  903. if (Uri[Index] == ':') {
  904. break;
  905. }
  906. if (Uri[Index] >= 'A' && Uri[Index] <= 'Z') {
  907. Uri[Index] -= (CHAR8)('A' - 'a');
  908. }
  909. }
  910. //
  911. // Return EFI_INVALID_PARAMETER if the URI is not HTTP or HTTPS.
  912. //
  913. if ((AsciiStrnCmp (Uri, "http://", 7) != 0) && (AsciiStrnCmp (Uri, "https://", 8) != 0)) {
  914. DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: Invalid Uri.\n"));
  915. return EFI_INVALID_PARAMETER;
  916. }
  917. //
  918. // HTTP is disabled, return EFI_ACCESS_DENIED if the URI is HTTP.
  919. //
  920. if (!PcdGetBool (PcdAllowHttpConnections) && (AsciiStrnCmp (Uri, "http://", 7) == 0)) {
  921. DEBUG ((EFI_D_ERROR, "HttpBootCheckUriScheme: HTTP is disabled.\n"));
  922. return EFI_ACCESS_DENIED;
  923. }
  924. return Status;
  925. }
  926. /**
  927. Get the URI address string from the input device path.
  928. Caller need to free the buffer in the UriAddress pointer.
  929. @param[in] FilePath Pointer to the device path which contains a URI device path node.
  930. @param[out] UriAddress The URI address string extract from the device path.
  931. @retval EFI_SUCCESS The URI string is returned.
  932. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  933. **/
  934. EFI_STATUS
  935. HttpBootParseFilePath (
  936. IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
  937. OUT CHAR8 **UriAddress
  938. )
  939. {
  940. EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
  941. URI_DEVICE_PATH *UriDevicePath;
  942. CHAR8 *Uri;
  943. UINTN UriStrLength;
  944. if (FilePath == NULL) {
  945. return EFI_INVALID_PARAMETER;
  946. }
  947. *UriAddress = NULL;
  948. //
  949. // Extract the URI address from the FilePath
  950. //
  951. TempDevicePath = FilePath;
  952. while (!IsDevicePathEnd (TempDevicePath)) {
  953. if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
  954. (DevicePathSubType (TempDevicePath) == MSG_URI_DP)) {
  955. UriDevicePath = (URI_DEVICE_PATH*) TempDevicePath;
  956. //
  957. // UEFI Spec doesn't require the URI to be a NULL-terminated string
  958. // So we allocate a new buffer and always append a '\0' to it.
  959. //
  960. UriStrLength = DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
  961. if (UriStrLength == 0) {
  962. //
  963. // return a NULL UriAddress if it's a empty URI device path node.
  964. //
  965. break;
  966. }
  967. Uri = AllocatePool (UriStrLength + 1);
  968. if (Uri == NULL) {
  969. return EFI_OUT_OF_RESOURCES;
  970. }
  971. CopyMem (Uri, UriDevicePath->Uri, DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL));
  972. Uri[DevicePathNodeLength (UriDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL)] = '\0';
  973. *UriAddress = Uri;
  974. }
  975. TempDevicePath = NextDevicePathNode (TempDevicePath);
  976. }
  977. return EFI_SUCCESS;
  978. }
  979. /**
  980. This function returns the image type according to server replied HTTP message
  981. and also the image's URI info.
  982. @param[in] Uri The pointer to the image's URI string.
  983. @param[in] UriParser URI Parse result returned by NetHttpParseUrl().
  984. @param[in] HeaderCount Number of HTTP header structures in Headers list.
  985. @param[in] Headers Array containing list of HTTP headers.
  986. @param[out] ImageType The image type of the downloaded file.
  987. @retval EFI_SUCCESS The image type is returned in ImageType.
  988. @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL.
  989. @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL.
  990. @retval EFI_NOT_FOUND Failed to identify the image type.
  991. @retval Others Unexpect error happened.
  992. **/
  993. EFI_STATUS
  994. HttpBootCheckImageType (
  995. IN CHAR8 *Uri,
  996. IN VOID *UriParser,
  997. IN UINTN HeaderCount,
  998. IN EFI_HTTP_HEADER *Headers,
  999. OUT HTTP_BOOT_IMAGE_TYPE *ImageType
  1000. )
  1001. {
  1002. EFI_STATUS Status;
  1003. EFI_HTTP_HEADER *Header;
  1004. CHAR8 *FilePath;
  1005. CHAR8 *FilePost;
  1006. if (Uri == NULL || UriParser == NULL || ImageType == NULL) {
  1007. return EFI_INVALID_PARAMETER;
  1008. }
  1009. if (HeaderCount != 0 && Headers == NULL) {
  1010. return EFI_INVALID_PARAMETER;
  1011. }
  1012. //
  1013. // Determine the image type by the HTTP Content-Type header field first.
  1014. // "application/efi" -> EFI Image
  1015. // "application/vnd.efi-iso" -> CD/DVD Image
  1016. // "application/vnd.efi-img" -> Virtual Disk Image
  1017. //
  1018. Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE);
  1019. if (Header != NULL) {
  1020. if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) {
  1021. *ImageType = ImageTypeEfi;
  1022. return EFI_SUCCESS;
  1023. } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) {
  1024. *ImageType = ImageTypeVirtualCd;
  1025. return EFI_SUCCESS;
  1026. } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) {
  1027. *ImageType = ImageTypeVirtualDisk;
  1028. return EFI_SUCCESS;
  1029. }
  1030. }
  1031. //
  1032. // Determine the image type by file extension:
  1033. // *.efi -> EFI Image
  1034. // *.iso -> CD/DVD Image
  1035. // *.img -> Virtual Disk Image
  1036. //
  1037. Status = HttpUrlGetPath (
  1038. Uri,
  1039. UriParser,
  1040. &FilePath
  1041. );
  1042. if (EFI_ERROR (Status)) {
  1043. return Status;
  1044. }
  1045. FilePost = FilePath + AsciiStrLen (FilePath) - 4;
  1046. if (AsciiStrCmp (FilePost, ".efi") == 0) {
  1047. *ImageType = ImageTypeEfi;
  1048. } else if (AsciiStrCmp (FilePost, ".iso") == 0) {
  1049. *ImageType = ImageTypeVirtualCd;
  1050. } else if (AsciiStrCmp (FilePost, ".img") == 0) {
  1051. *ImageType = ImageTypeVirtualDisk;
  1052. } else {
  1053. *ImageType = ImageTypeMax;
  1054. }
  1055. FreePool (FilePath);
  1056. return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND;
  1057. }
  1058. /**
  1059. This function register the RAM disk info to the system.
  1060. @param[in] Private The pointer to the driver's private data.
  1061. @param[in] BufferSize The size of Buffer in bytes.
  1062. @param[in] Buffer The base address of the RAM disk.
  1063. @param[in] ImageType The image type of the file in Buffer.
  1064. @retval EFI_SUCCESS The RAM disk has been registered.
  1065. @retval EFI_NOT_FOUND No RAM disk protocol instances were found.
  1066. @retval EFI_UNSUPPORTED The ImageType is not supported.
  1067. @retval Others Unexpected error happened.
  1068. **/
  1069. EFI_STATUS
  1070. HttpBootRegisterRamDisk (
  1071. IN HTTP_BOOT_PRIVATE_DATA *Private,
  1072. IN UINTN BufferSize,
  1073. IN VOID *Buffer,
  1074. IN HTTP_BOOT_IMAGE_TYPE ImageType
  1075. )
  1076. {
  1077. EFI_RAM_DISK_PROTOCOL *RamDisk;
  1078. EFI_STATUS Status;
  1079. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  1080. EFI_GUID *RamDiskType;
  1081. ASSERT (Private != NULL);
  1082. ASSERT (Buffer != NULL);
  1083. ASSERT (BufferSize != 0);
  1084. Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID**) &RamDisk);
  1085. if (EFI_ERROR (Status)) {
  1086. DEBUG ((EFI_D_ERROR, "HTTP Boot: Couldn't find the RAM Disk protocol - %r\n", Status));
  1087. return Status;
  1088. }
  1089. if (ImageType == ImageTypeVirtualCd) {
  1090. RamDiskType = &gEfiVirtualCdGuid;
  1091. } else if (ImageType == ImageTypeVirtualDisk) {
  1092. RamDiskType = &gEfiVirtualDiskGuid;
  1093. } else {
  1094. return EFI_UNSUPPORTED;
  1095. }
  1096. Status = RamDisk->Register (
  1097. (UINTN)Buffer,
  1098. (UINT64)BufferSize,
  1099. RamDiskType,
  1100. Private->UsingIpv6 ? Private->Ip6Nic->DevicePath : Private->Ip4Nic->DevicePath,
  1101. &DevicePath
  1102. );
  1103. if (EFI_ERROR (Status)) {
  1104. DEBUG ((EFI_D_ERROR, "HTTP Boot: Failed to register RAM Disk - %r\n", Status));
  1105. }
  1106. return Status;
  1107. }
  1108. /**
  1109. Indicate if the HTTP status code indicates a redirection.
  1110. @param[in] StatusCode HTTP status code from server.
  1111. @return TRUE if it's redirection.
  1112. **/
  1113. BOOLEAN
  1114. HttpBootIsHttpRedirectStatusCode (
  1115. IN EFI_HTTP_STATUS_CODE StatusCode
  1116. )
  1117. {
  1118. if (StatusCode == HTTP_STATUS_301_MOVED_PERMANENTLY ||
  1119. StatusCode == HTTP_STATUS_302_FOUND ||
  1120. StatusCode == HTTP_STATUS_307_TEMPORARY_REDIRECT ||
  1121. StatusCode == HTTP_STATUS_308_PERMANENT_REDIRECT) {
  1122. return TRUE;
  1123. }
  1124. return FALSE;
  1125. }