HttpBootDhcp6.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. /** @file
  2. Functions implementation related with DHCPv6 for HTTP boot driver.
  3. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "HttpBootDxe.h"
  7. /**
  8. Build the options buffer for the DHCPv6 request packet.
  9. @param[in] Private The pointer to HTTP BOOT driver private data.
  10. @param[out] OptList The pointer to the option pointer array.
  11. @param[in] Buffer The pointer to the buffer to contain the option list.
  12. @return Index The count of the built-in options.
  13. **/
  14. UINT32
  15. HttpBootBuildDhcp6Options (
  16. IN HTTP_BOOT_PRIVATE_DATA *Private,
  17. OUT EFI_DHCP6_PACKET_OPTION **OptList,
  18. IN UINT8 *Buffer
  19. )
  20. {
  21. HTTP_BOOT_DHCP6_OPTION_ENTRY OptEnt;
  22. UINT16 Value;
  23. UINT32 Index;
  24. Index = 0;
  25. OptList[0] = (EFI_DHCP6_PACKET_OPTION *)Buffer;
  26. //
  27. // Append client option request option
  28. //
  29. OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO);
  30. OptList[Index]->OpLen = HTONS (8);
  31. OptEnt.Oro = (HTTP_BOOT_DHCP6_OPTION_ORO *)OptList[Index]->Data;
  32. OptEnt.Oro->OpCode[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL);
  33. OptEnt.Oro->OpCode[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM);
  34. OptEnt.Oro->OpCode[2] = HTONS (DHCP6_OPT_DNS_SERVERS);
  35. OptEnt.Oro->OpCode[3] = HTONS (DHCP6_OPT_VENDOR_CLASS);
  36. Index++;
  37. OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
  38. //
  39. // Append client network device interface option
  40. //
  41. OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI);
  42. OptList[Index]->OpLen = HTONS ((UINT16)3);
  43. OptEnt.Undi = (HTTP_BOOT_DHCP6_OPTION_UNDI *)OptList[Index]->Data;
  44. if (Private->Nii != NULL) {
  45. OptEnt.Undi->Type = Private->Nii->Type;
  46. OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
  47. OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
  48. } else {
  49. OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
  50. OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
  51. OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
  52. }
  53. Index++;
  54. OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
  55. //
  56. // Append client system architecture option
  57. //
  58. OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH);
  59. OptList[Index]->OpLen = HTONS ((UINT16)sizeof (HTTP_BOOT_DHCP6_OPTION_ARCH));
  60. OptEnt.Arch = (HTTP_BOOT_DHCP6_OPTION_ARCH *)OptList[Index]->Data;
  61. Value = HTONS (EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE);
  62. CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
  63. Index++;
  64. OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
  65. //
  66. // Append vendor class identify option.
  67. //
  68. OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS);
  69. OptList[Index]->OpLen = HTONS ((UINT16)sizeof (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS));
  70. OptEnt.VendorClass = (HTTP_BOOT_DHCP6_OPTION_VENDOR_CLASS *)OptList[Index]->Data;
  71. OptEnt.VendorClass->Vendor = HTONL (HTTP_BOOT_DHCP6_ENTERPRISE_NUM);
  72. OptEnt.VendorClass->ClassLen = HTONS ((UINT16)sizeof (HTTP_BOOT_CLASS_ID));
  73. CopyMem (
  74. &OptEnt.VendorClass->ClassId,
  75. DEFAULT_CLASS_ID_DATA,
  76. sizeof (HTTP_BOOT_CLASS_ID)
  77. );
  78. HttpBootUintnToAscDecWithFormat (
  79. EFI_HTTP_BOOT_CLIENT_SYSTEM_ARCHITECTURE,
  80. OptEnt.VendorClass->ClassId.ArchitectureType,
  81. sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)
  82. );
  83. if (Private->Nii != NULL) {
  84. CopyMem (
  85. OptEnt.VendorClass->ClassId.InterfaceName,
  86. Private->Nii->StringId,
  87. sizeof (OptEnt.VendorClass->ClassId.InterfaceName)
  88. );
  89. HttpBootUintnToAscDecWithFormat (
  90. Private->Nii->MajorVer,
  91. OptEnt.VendorClass->ClassId.UndiMajor,
  92. sizeof (OptEnt.VendorClass->ClassId.UndiMajor)
  93. );
  94. HttpBootUintnToAscDecWithFormat (
  95. Private->Nii->MinorVer,
  96. OptEnt.VendorClass->ClassId.UndiMinor,
  97. sizeof (OptEnt.VendorClass->ClassId.UndiMinor)
  98. );
  99. }
  100. Index++;
  101. return Index;
  102. }
  103. /**
  104. Parse out a DHCPv6 option by OptTag, and find the position in buffer.
  105. @param[in] Buffer The pointer to the option buffer.
  106. @param[in] Length Length of the option buffer.
  107. @param[in] OptTag The required option tag.
  108. @retval NULL Failed to parse the required option.
  109. @retval Others The position of the required option in buffer.
  110. **/
  111. EFI_DHCP6_PACKET_OPTION *
  112. HttpBootParseDhcp6Options (
  113. IN UINT8 *Buffer,
  114. IN UINT32 Length,
  115. IN UINT16 OptTag
  116. )
  117. {
  118. EFI_DHCP6_PACKET_OPTION *Option;
  119. UINT32 Offset;
  120. Option = (EFI_DHCP6_PACKET_OPTION *)Buffer;
  121. Offset = 0;
  122. //
  123. // OpLen and OpCode here are both stored in network order.
  124. //
  125. while (Offset < Length) {
  126. if (NTOHS (Option->OpCode) == OptTag) {
  127. return Option;
  128. }
  129. Offset += (NTOHS (Option->OpLen) + 4);
  130. Option = (EFI_DHCP6_PACKET_OPTION *)(Buffer + Offset);
  131. }
  132. return NULL;
  133. }
  134. /**
  135. Parse the cached DHCPv6 packet, including all the options.
  136. @param[in] Cache6 The pointer to a cached DHCPv6 packet.
  137. @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
  138. @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
  139. **/
  140. EFI_STATUS
  141. HttpBootParseDhcp6Packet (
  142. IN HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6
  143. )
  144. {
  145. EFI_DHCP6_PACKET *Offer;
  146. EFI_DHCP6_PACKET_OPTION **Options;
  147. EFI_DHCP6_PACKET_OPTION *Option;
  148. HTTP_BOOT_OFFER_TYPE OfferType;
  149. EFI_IPv6_ADDRESS IpAddr;
  150. BOOLEAN IsProxyOffer;
  151. BOOLEAN IsHttpOffer;
  152. BOOLEAN IsDnsOffer;
  153. BOOLEAN IpExpressedUri;
  154. EFI_STATUS Status;
  155. UINT32 Offset;
  156. UINT32 Length;
  157. IsDnsOffer = FALSE;
  158. IpExpressedUri = FALSE;
  159. IsProxyOffer = TRUE;
  160. IsHttpOffer = FALSE;
  161. Offer = &Cache6->Packet.Offer;
  162. Options = Cache6->OptList;
  163. ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));
  164. Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option);
  165. Offset = 0;
  166. Length = GET_DHCP6_OPTION_SIZE (Offer);
  167. //
  168. // OpLen and OpCode here are both stored in network order, since they are from original packet.
  169. //
  170. while (Offset < Length) {
  171. if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) {
  172. Options[HTTP_BOOT_DHCP6_IDX_IA_NA] = Option;
  173. } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) {
  174. //
  175. // The server sends this option to inform the client about an URL to a boot file.
  176. //
  177. Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] = Option;
  178. } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) {
  179. Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_PARAM] = Option;
  180. } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {
  181. Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS] = Option;
  182. } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {
  183. Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER] = Option;
  184. }
  185. Offset += (NTOHS (Option->OpLen) + 4);
  186. Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option + Offset);
  187. }
  188. //
  189. // The offer with assigned client address is NOT a proxy offer.
  190. // An ia_na option, embedded with valid ia_addr option and a status_code of success.
  191. //
  192. Option = Options[HTTP_BOOT_DHCP6_IDX_IA_NA];
  193. if (Option != NULL) {
  194. Option = HttpBootParseDhcp6Options (
  195. Option->Data + 12,
  196. NTOHS (Option->OpLen),
  197. DHCP6_OPT_STATUS_CODE
  198. );
  199. if (((Option != NULL) && (Option->Data[0] == 0)) || (Option == NULL)) {
  200. IsProxyOffer = FALSE;
  201. }
  202. }
  203. //
  204. // The offer with "HTTPClient" is a Http offer.
  205. //
  206. Option = Options[HTTP_BOOT_DHCP6_IDX_VENDOR_CLASS];
  207. if ((Option != NULL) &&
  208. (NTOHS (Option->OpLen) >= 16) &&
  209. (CompareMem ((Option->Data + 6), DEFAULT_CLASS_ID_DATA, 10) == 0))
  210. {
  211. IsHttpOffer = TRUE;
  212. }
  213. //
  214. // The offer with Domain Server is a DNS offer.
  215. //
  216. Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];
  217. if (Option != NULL) {
  218. IsDnsOffer = TRUE;
  219. }
  220. //
  221. // Http offer must have a boot URI.
  222. //
  223. if (IsHttpOffer && (Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL)) {
  224. return EFI_DEVICE_ERROR;
  225. }
  226. //
  227. // Try to retrieve the IP of HTTP server from URI.
  228. //
  229. if (IsHttpOffer) {
  230. Status = HttpParseUrl (
  231. (CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
  232. (UINT32)AsciiStrLen ((CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data),
  233. FALSE,
  234. &Cache6->UriParser
  235. );
  236. if (EFI_ERROR (Status)) {
  237. return EFI_DEVICE_ERROR;
  238. }
  239. Status = HttpUrlGetIp6 (
  240. (CHAR8 *)Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
  241. Cache6->UriParser,
  242. &IpAddr
  243. );
  244. IpExpressedUri = !EFI_ERROR (Status);
  245. }
  246. //
  247. // Determine offer type of the DHCPv6 packet.
  248. //
  249. if (IsHttpOffer) {
  250. if (IpExpressedUri) {
  251. if (IsProxyOffer) {
  252. OfferType = HttpOfferTypeProxyIpUri;
  253. } else {
  254. OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;
  255. }
  256. } else {
  257. if (!IsProxyOffer) {
  258. OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;
  259. } else {
  260. OfferType = HttpOfferTypeProxyNameUri;
  261. }
  262. }
  263. } else {
  264. if (!IsProxyOffer) {
  265. OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;
  266. } else {
  267. return EFI_DEVICE_ERROR;
  268. }
  269. }
  270. Cache6->OfferType = OfferType;
  271. return EFI_SUCCESS;
  272. }
  273. /**
  274. Cache the DHCPv6 packet.
  275. @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
  276. @param[in] Src The pointer to the DHCPv6 packet to be cached.
  277. @retval EFI_SUCCESS Packet is copied.
  278. @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
  279. **/
  280. EFI_STATUS
  281. HttpBootCacheDhcp6Packet (
  282. IN EFI_DHCP6_PACKET *Dst,
  283. IN EFI_DHCP6_PACKET *Src
  284. )
  285. {
  286. if (Dst->Size < Src->Length) {
  287. return EFI_BUFFER_TOO_SMALL;
  288. }
  289. CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);
  290. Dst->Length = Src->Length;
  291. return EFI_SUCCESS;
  292. }
  293. /**
  294. Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
  295. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  296. @param[in] RcvdOffer The pointer to the received offer packet.
  297. @retval EFI_SUCCESS Cache and parse the packet successfully.
  298. @retval Others Operation failed.
  299. **/
  300. EFI_STATUS
  301. HttpBootCacheDhcp6Offer (
  302. IN HTTP_BOOT_PRIVATE_DATA *Private,
  303. IN EFI_DHCP6_PACKET *RcvdOffer
  304. )
  305. {
  306. HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6;
  307. EFI_DHCP6_PACKET *Offer;
  308. HTTP_BOOT_OFFER_TYPE OfferType;
  309. EFI_STATUS Status;
  310. Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;
  311. Offer = &Cache6->Packet.Offer;
  312. //
  313. // Cache the content of DHCPv6 packet firstly.
  314. //
  315. Status = HttpBootCacheDhcp6Packet (Offer, RcvdOffer);
  316. if (EFI_ERROR (Status)) {
  317. return Status;
  318. }
  319. //
  320. // Validate the DHCPv6 packet, and parse the options and offer type.
  321. //
  322. if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) {
  323. return EFI_ABORTED;
  324. }
  325. //
  326. // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
  327. //
  328. OfferType = Cache6->OfferType;
  329. ASSERT (OfferType < HttpOfferTypeMax);
  330. ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);
  331. Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
  332. Private->OfferCount[OfferType]++;
  333. Private->OfferNum++;
  334. return EFI_SUCCESS;
  335. }
  336. /**
  337. EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
  338. to intercept events that occurred in the configuration process.
  339. @param[in] This The pointer to the EFI DHCPv6 Protocol.
  340. @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
  341. @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
  342. @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
  343. state transition.
  344. @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
  345. @param[out] NewPacket The packet that is used to replace the Packet above.
  346. @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
  347. @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
  348. driver will continue to wait for more packets.
  349. @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
  350. @retval EFI_OUT_OF_RESOURCES There are not enough resources.
  351. **/
  352. EFI_STATUS
  353. EFIAPI
  354. HttpBootDhcp6CallBack (
  355. IN EFI_DHCP6_PROTOCOL *This,
  356. IN VOID *Context,
  357. IN EFI_DHCP6_STATE CurrentState,
  358. IN EFI_DHCP6_EVENT Dhcp6Event,
  359. IN EFI_DHCP6_PACKET *Packet,
  360. OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL
  361. )
  362. {
  363. HTTP_BOOT_PRIVATE_DATA *Private;
  364. EFI_DHCP6_PACKET *SelectAd;
  365. EFI_STATUS Status;
  366. BOOLEAN Received;
  367. if ((Dhcp6Event != Dhcp6SendSolicit) &&
  368. (Dhcp6Event != Dhcp6RcvdAdvertise) &&
  369. (Dhcp6Event != Dhcp6SendRequest) &&
  370. (Dhcp6Event != Dhcp6RcvdReply) &&
  371. (Dhcp6Event != Dhcp6SelectAdvertise))
  372. {
  373. return EFI_SUCCESS;
  374. }
  375. ASSERT (Packet != NULL);
  376. Private = (HTTP_BOOT_PRIVATE_DATA *)Context;
  377. Status = EFI_SUCCESS;
  378. if ((Private->HttpBootCallback != NULL) && (Dhcp6Event != Dhcp6SelectAdvertise)) {
  379. Received = (BOOLEAN)(Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);
  380. Status = Private->HttpBootCallback->Callback (
  381. Private->HttpBootCallback,
  382. HttpBootDhcp6,
  383. Received,
  384. Packet->Length,
  385. &Packet->Dhcp6
  386. );
  387. if (EFI_ERROR (Status)) {
  388. return EFI_ABORTED;
  389. }
  390. }
  391. switch (Dhcp6Event) {
  392. case Dhcp6RcvdAdvertise:
  393. Status = EFI_NOT_READY;
  394. if (Packet->Length > HTTP_BOOT_DHCP6_PACKET_MAX_SIZE) {
  395. //
  396. // Ignore the incoming packets which exceed the maximum length.
  397. //
  398. break;
  399. }
  400. if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {
  401. //
  402. // Cache the dhcp offers to OfferBuffer[] for select later, and record
  403. // the OfferIndex and OfferCount.
  404. // If error happens, just ignore this packet and continue to wait more offer.
  405. //
  406. HttpBootCacheDhcp6Offer (Private, Packet);
  407. }
  408. break;
  409. case Dhcp6SelectAdvertise:
  410. //
  411. // Select offer by the default policy or by order, and record the SelectIndex
  412. // and SelectProxyType.
  413. //
  414. HttpBootSelectDhcpOffer (Private);
  415. if (Private->SelectIndex == 0) {
  416. Status = EFI_ABORTED;
  417. } else {
  418. ASSERT (NewPacket != NULL);
  419. SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;
  420. *NewPacket = AllocateZeroPool (SelectAd->Size);
  421. if (*NewPacket == NULL) {
  422. return EFI_OUT_OF_RESOURCES;
  423. }
  424. CopyMem (*NewPacket, SelectAd, SelectAd->Size);
  425. }
  426. break;
  427. default:
  428. break;
  429. }
  430. return Status;
  431. }
  432. /**
  433. Check whether IP driver could route the message which will be sent to ServerIp address.
  434. This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
  435. route is found in IP6 route table, the address will be filed in GatewayAddr and return.
  436. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  437. @param[in] TimeOutInSecond Timeout value in seconds.
  438. @param[out] GatewayAddr Pointer to store the gateway IP address.
  439. @retval EFI_SUCCESS Found a valid gateway address successfully.
  440. @retval EFI_TIMEOUT The operation is time out.
  441. @retval Other Unexpected error happened.
  442. **/
  443. EFI_STATUS
  444. HttpBootCheckRouteTable (
  445. IN HTTP_BOOT_PRIVATE_DATA *Private,
  446. IN UINTN TimeOutInSecond,
  447. OUT EFI_IPv6_ADDRESS *GatewayAddr
  448. )
  449. {
  450. EFI_STATUS Status;
  451. EFI_IP6_PROTOCOL *Ip6;
  452. EFI_IP6_MODE_DATA Ip6ModeData;
  453. UINTN Index;
  454. EFI_EVENT TimeOutEvt;
  455. UINTN RetryCount;
  456. BOOLEAN GatewayIsFound;
  457. ASSERT (GatewayAddr != NULL);
  458. ASSERT (Private != NULL);
  459. Ip6 = Private->Ip6;
  460. GatewayIsFound = FALSE;
  461. RetryCount = 0;
  462. TimeOutEvt = NULL;
  463. Status = EFI_SUCCESS;
  464. ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
  465. while (TRUE) {
  466. Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
  467. if (EFI_ERROR (Status)) {
  468. goto ON_EXIT;
  469. }
  470. //
  471. // Find out the gateway address which can route the message which send to ServerIp.
  472. //
  473. for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
  474. if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
  475. IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
  476. GatewayIsFound = TRUE;
  477. break;
  478. }
  479. }
  480. if (Ip6ModeData.AddressList != NULL) {
  481. FreePool (Ip6ModeData.AddressList);
  482. }
  483. if (Ip6ModeData.GroupTable != NULL) {
  484. FreePool (Ip6ModeData.GroupTable);
  485. }
  486. if (Ip6ModeData.RouteTable != NULL) {
  487. FreePool (Ip6ModeData.RouteTable);
  488. }
  489. if (Ip6ModeData.NeighborCache != NULL) {
  490. FreePool (Ip6ModeData.NeighborCache);
  491. }
  492. if (Ip6ModeData.PrefixTable != NULL) {
  493. FreePool (Ip6ModeData.PrefixTable);
  494. }
  495. if (Ip6ModeData.IcmpTypeList != NULL) {
  496. FreePool (Ip6ModeData.IcmpTypeList);
  497. }
  498. if (GatewayIsFound || (RetryCount == TimeOutInSecond)) {
  499. break;
  500. }
  501. RetryCount++;
  502. //
  503. // Delay 1 second then recheck it again.
  504. //
  505. if (TimeOutEvt == NULL) {
  506. Status = gBS->CreateEvent (
  507. EVT_TIMER,
  508. TPL_CALLBACK,
  509. NULL,
  510. NULL,
  511. &TimeOutEvt
  512. );
  513. if (EFI_ERROR (Status)) {
  514. goto ON_EXIT;
  515. }
  516. }
  517. Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
  518. if (EFI_ERROR (Status)) {
  519. goto ON_EXIT;
  520. }
  521. while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
  522. Ip6->Poll (Ip6);
  523. }
  524. }
  525. ON_EXIT:
  526. if (TimeOutEvt != NULL) {
  527. gBS->CloseEvent (TimeOutEvt);
  528. }
  529. if (GatewayIsFound) {
  530. Status = EFI_SUCCESS;
  531. } else if (RetryCount == TimeOutInSecond) {
  532. Status = EFI_TIMEOUT;
  533. }
  534. return Status;
  535. }
  536. /**
  537. Set the IP6 policy to Automatic.
  538. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  539. @retval EFI_SUCCESS Switch the IP policy successfully.
  540. @retval Others Unexpected error happened.
  541. **/
  542. EFI_STATUS
  543. HttpBootSetIp6Policy (
  544. IN HTTP_BOOT_PRIVATE_DATA *Private
  545. )
  546. {
  547. EFI_IP6_CONFIG_POLICY Policy;
  548. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  549. EFI_STATUS Status;
  550. UINTN DataSize;
  551. Ip6Config = Private->Ip6Config;
  552. DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
  553. //
  554. // Get and store the current policy of IP6 driver.
  555. //
  556. Status = Ip6Config->GetData (
  557. Ip6Config,
  558. Ip6ConfigDataTypePolicy,
  559. &DataSize,
  560. &Policy
  561. );
  562. if (EFI_ERROR (Status)) {
  563. return Status;
  564. }
  565. if (Policy == Ip6ConfigPolicyManual) {
  566. Policy = Ip6ConfigPolicyAutomatic;
  567. Status = Ip6Config->SetData (
  568. Ip6Config,
  569. Ip6ConfigDataTypePolicy,
  570. sizeof (EFI_IP6_CONFIG_POLICY),
  571. &Policy
  572. );
  573. if (EFI_ERROR (Status)) {
  574. return Status;
  575. }
  576. }
  577. return EFI_SUCCESS;
  578. }
  579. /**
  580. This function will register the default DNS addresses to the network device.
  581. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  582. @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
  583. @param[in] DnsServerData Point a list of DNS server address in an array
  584. of EFI_IPv6_ADDRESS instances.
  585. @retval EFI_SUCCESS The DNS configuration has been configured successfully.
  586. @retval Others Failed to configure the address.
  587. **/
  588. EFI_STATUS
  589. HttpBootSetIp6Dns (
  590. IN HTTP_BOOT_PRIVATE_DATA *Private,
  591. IN UINTN DataLength,
  592. IN VOID *DnsServerData
  593. )
  594. {
  595. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  596. ASSERT (Private->UsingIpv6);
  597. Ip6Config = Private->Ip6Config;
  598. return Ip6Config->SetData (
  599. Ip6Config,
  600. Ip6ConfigDataTypeDnsServer,
  601. DataLength,
  602. DnsServerData
  603. );
  604. }
  605. /**
  606. This function will register the IPv6 gateway address to the network device.
  607. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  608. @retval EFI_SUCCESS The new IP configuration has been configured successfully.
  609. @retval Others Failed to configure the address.
  610. **/
  611. EFI_STATUS
  612. HttpBootSetIp6Gateway (
  613. IN HTTP_BOOT_PRIVATE_DATA *Private
  614. )
  615. {
  616. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  617. EFI_STATUS Status;
  618. ASSERT (Private->UsingIpv6);
  619. Ip6Config = Private->Ip6Config;
  620. //
  621. // Set the default gateway address.
  622. //
  623. if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) {
  624. Status = Ip6Config->SetData (
  625. Ip6Config,
  626. Ip6ConfigDataTypeGateway,
  627. sizeof (EFI_IPv6_ADDRESS),
  628. &Private->GatewayIp.v6
  629. );
  630. if (EFI_ERROR (Status)) {
  631. return Status;
  632. }
  633. }
  634. return EFI_SUCCESS;
  635. }
  636. /**
  637. This function will register the station IP address.
  638. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  639. @retval EFI_SUCCESS The new IP address has been configured successfully.
  640. @retval Others Failed to configure the address.
  641. **/
  642. EFI_STATUS
  643. HttpBootSetIp6Address (
  644. IN HTTP_BOOT_PRIVATE_DATA *Private
  645. )
  646. {
  647. EFI_STATUS Status;
  648. EFI_IP6_PROTOCOL *Ip6;
  649. EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
  650. EFI_IP6_CONFIG_POLICY Policy;
  651. EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
  652. EFI_IPv6_ADDRESS *Ip6Addr;
  653. EFI_IPv6_ADDRESS GatewayAddr;
  654. EFI_IP6_CONFIG_DATA Ip6CfgData;
  655. EFI_EVENT MappedEvt;
  656. UINTN DataSize;
  657. BOOLEAN IsAddressOk;
  658. UINTN Index;
  659. ASSERT (Private->UsingIpv6);
  660. MappedEvt = NULL;
  661. IsAddressOk = FALSE;
  662. Ip6Addr = NULL;
  663. Ip6Cfg = Private->Ip6Config;
  664. Ip6 = Private->Ip6;
  665. ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
  666. CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
  667. ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA));
  668. Ip6CfgData.AcceptIcmpErrors = TRUE;
  669. Ip6CfgData.DefaultProtocol = IP6_ICMP;
  670. Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT;
  671. Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME;
  672. Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME;
  673. Status = Ip6->Configure (Ip6, &Ip6CfgData);
  674. if (EFI_ERROR (Status)) {
  675. goto ON_EXIT;
  676. }
  677. //
  678. // Retrieve the gateway address from IP6 route table.
  679. //
  680. Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
  681. if (EFI_ERROR (Status)) {
  682. Private->NoGateway = TRUE;
  683. } else {
  684. IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr);
  685. }
  686. //
  687. // Set the new address by Ip6ConfigProtocol manually.
  688. //
  689. Policy = Ip6ConfigPolicyManual;
  690. Status = Ip6Cfg->SetData (
  691. Ip6Cfg,
  692. Ip6ConfigDataTypePolicy,
  693. sizeof (EFI_IP6_CONFIG_POLICY),
  694. &Policy
  695. );
  696. if (EFI_ERROR (Status)) {
  697. goto ON_EXIT;
  698. }
  699. //
  700. // Create a notify event to set address flag when DAD if IP6 driver succeeded.
  701. //
  702. Status = gBS->CreateEvent (
  703. EVT_NOTIFY_SIGNAL,
  704. TPL_NOTIFY,
  705. HttpBootCommonNotify,
  706. &IsAddressOk,
  707. &MappedEvt
  708. );
  709. if (EFI_ERROR (Status)) {
  710. goto ON_EXIT;
  711. }
  712. //
  713. // Set static host ip6 address. This is a asynchronous process.
  714. //
  715. Status = Ip6Cfg->RegisterDataNotify (
  716. Ip6Cfg,
  717. Ip6ConfigDataTypeManualAddress,
  718. MappedEvt
  719. );
  720. if (EFI_ERROR (Status)) {
  721. goto ON_EXIT;
  722. }
  723. Status = Ip6Cfg->SetData (
  724. Ip6Cfg,
  725. Ip6ConfigDataTypeManualAddress,
  726. sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),
  727. &CfgAddr
  728. );
  729. if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
  730. goto ON_EXIT;
  731. } else if (Status == EFI_NOT_READY) {
  732. //
  733. // Poll the network until the asynchronous process is finished.
  734. //
  735. while (!IsAddressOk) {
  736. Ip6->Poll (Ip6);
  737. }
  738. //
  739. // Check whether the Ip6 Address setting is successed.
  740. //
  741. DataSize = 0;
  742. Status = Ip6Cfg->GetData (
  743. Ip6Cfg,
  744. Ip6ConfigDataTypeManualAddress,
  745. &DataSize,
  746. NULL
  747. );
  748. if ((Status != EFI_BUFFER_TOO_SMALL) || (DataSize == 0)) {
  749. Status = EFI_DEVICE_ERROR;
  750. goto ON_EXIT;
  751. }
  752. Ip6Addr = AllocatePool (DataSize);
  753. if (Ip6Addr == NULL) {
  754. return EFI_OUT_OF_RESOURCES;
  755. }
  756. Status = Ip6Cfg->GetData (
  757. Ip6Cfg,
  758. Ip6ConfigDataTypeManualAddress,
  759. &DataSize,
  760. (VOID *)Ip6Addr
  761. );
  762. if (EFI_ERROR (Status)) {
  763. Status = EFI_DEVICE_ERROR;
  764. goto ON_EXIT;
  765. }
  766. for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) {
  767. if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) {
  768. break;
  769. }
  770. }
  771. if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {
  772. Status = EFI_ABORTED;
  773. goto ON_EXIT;
  774. }
  775. }
  776. ON_EXIT:
  777. if (MappedEvt != NULL) {
  778. Ip6Cfg->UnregisterDataNotify (
  779. Ip6Cfg,
  780. Ip6ConfigDataTypeManualAddress,
  781. MappedEvt
  782. );
  783. gBS->CloseEvent (MappedEvt);
  784. }
  785. if (Ip6Addr != NULL) {
  786. FreePool (Ip6Addr);
  787. }
  788. return Status;
  789. }
  790. /**
  791. Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
  792. @param[in] Private Pointer to HTTP_BOOT private data.
  793. @retval EFI_SUCCESS The S.A.R.R process successfully finished.
  794. @retval Others Failed to finish the S.A.R.R process.
  795. **/
  796. EFI_STATUS
  797. HttpBootDhcp6Sarr (
  798. IN HTTP_BOOT_PRIVATE_DATA *Private
  799. )
  800. {
  801. EFI_DHCP6_PROTOCOL *Dhcp6;
  802. EFI_DHCP6_CONFIG_DATA Config;
  803. EFI_DHCP6_MODE_DATA Mode;
  804. EFI_DHCP6_RETRANSMISSION *Retransmit;
  805. EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM];
  806. UINT32 OptCount;
  807. UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];
  808. EFI_STATUS Status;
  809. Dhcp6 = Private->Dhcp6;
  810. ASSERT (Dhcp6 != NULL);
  811. //
  812. // Build options list for the request packet.
  813. //
  814. OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer);
  815. ASSERT (OptCount > 0);
  816. Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
  817. if (Retransmit == NULL) {
  818. return EFI_OUT_OF_RESOURCES;
  819. }
  820. ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));
  821. ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
  822. Config.OptionCount = OptCount;
  823. Config.OptionList = OptList;
  824. Config.Dhcp6Callback = HttpBootDhcp6CallBack;
  825. Config.CallbackContext = Private;
  826. Config.IaInfoEvent = NULL;
  827. Config.RapidCommit = FALSE;
  828. Config.ReconfigureAccept = FALSE;
  829. Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ());
  830. Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
  831. Config.SolicitRetransmission = Retransmit;
  832. Retransmit->Irt = 4;
  833. Retransmit->Mrc = 4;
  834. Retransmit->Mrt = 32;
  835. Retransmit->Mrd = 60;
  836. //
  837. // Configure the DHCPv6 instance for HTTP boot.
  838. //
  839. Status = Dhcp6->Configure (Dhcp6, &Config);
  840. FreePool (Retransmit);
  841. if (EFI_ERROR (Status)) {
  842. goto ON_EXIT;
  843. }
  844. //
  845. // Initialize the record fields for DHCPv6 offer in private data.
  846. //
  847. Private->OfferNum = 0;
  848. Private->SelectIndex = 0;
  849. ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
  850. ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
  851. //
  852. // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
  853. //
  854. Status = Dhcp6->Start (Dhcp6);
  855. if (EFI_ERROR (Status)) {
  856. goto ON_EXIT;
  857. }
  858. //
  859. // Get the acquired IPv6 address and store them.
  860. //
  861. Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);
  862. if (EFI_ERROR (Status)) {
  863. goto ON_EXIT;
  864. }
  865. ASSERT (Mode.Ia->State == Dhcp6Bound);
  866. CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
  867. AsciiPrint ("\n Station IPv6 address is ");
  868. HttpBootShowIp6Addr (&Private->StationIp.v6);
  869. AsciiPrint ("\n");
  870. ON_EXIT:
  871. if (EFI_ERROR (Status)) {
  872. Dhcp6->Stop (Dhcp6);
  873. Dhcp6->Configure (Dhcp6, NULL);
  874. } else {
  875. ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
  876. Dhcp6->Configure (Dhcp6, &Config);
  877. if (Mode.ClientId != NULL) {
  878. FreePool (Mode.ClientId);
  879. }
  880. if (Mode.Ia != NULL) {
  881. FreePool (Mode.Ia);
  882. }
  883. }
  884. return Status;
  885. }