HttpBootDhcp6.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  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 postion 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, embeded 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. IsHttpOffer = TRUE;
  211. }
  212. //
  213. // The offer with Domain Server is a DNS offer.
  214. //
  215. Option = Options[HTTP_BOOT_DHCP6_IDX_DNS_SERVER];
  216. if (Option != NULL) {
  217. IsDnsOffer = TRUE;
  218. }
  219. //
  220. // Http offer must have a boot URI.
  221. //
  222. if (IsHttpOffer && Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
  223. return EFI_DEVICE_ERROR;
  224. }
  225. //
  226. // Try to retrieve the IP of HTTP server from URI.
  227. //
  228. if (IsHttpOffer) {
  229. Status = HttpParseUrl (
  230. (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
  231. (UINT32) AsciiStrLen ((CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data),
  232. FALSE,
  233. &Cache6->UriParser
  234. );
  235. if (EFI_ERROR (Status)) {
  236. return EFI_DEVICE_ERROR;
  237. }
  238. Status = HttpUrlGetIp6 (
  239. (CHAR8*) Options[HTTP_BOOT_DHCP6_IDX_BOOT_FILE_URL]->Data,
  240. Cache6->UriParser,
  241. &IpAddr
  242. );
  243. IpExpressedUri = !EFI_ERROR (Status);
  244. }
  245. //
  246. // Determine offer type of the DHCPv6 packet.
  247. //
  248. if (IsHttpOffer) {
  249. if (IpExpressedUri) {
  250. if (IsProxyOffer) {
  251. OfferType = HttpOfferTypeProxyIpUri;
  252. } else {
  253. OfferType = IsDnsOffer ? HttpOfferTypeDhcpIpUriDns : HttpOfferTypeDhcpIpUri;
  254. }
  255. } else {
  256. if (!IsProxyOffer) {
  257. OfferType = IsDnsOffer ? HttpOfferTypeDhcpNameUriDns : HttpOfferTypeDhcpNameUri;
  258. } else {
  259. OfferType = HttpOfferTypeProxyNameUri;
  260. }
  261. }
  262. } else {
  263. if (!IsProxyOffer) {
  264. OfferType = IsDnsOffer ? HttpOfferTypeDhcpDns : HttpOfferTypeDhcpOnly;
  265. } else {
  266. return EFI_DEVICE_ERROR;
  267. }
  268. }
  269. Cache6->OfferType = OfferType;
  270. return EFI_SUCCESS;
  271. }
  272. /**
  273. Cache the DHCPv6 packet.
  274. @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
  275. @param[in] Src The pointer to the DHCPv6 packet to be cached.
  276. @retval EFI_SUCCESS Packet is copied.
  277. @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
  278. **/
  279. EFI_STATUS
  280. HttpBootCacheDhcp6Packet (
  281. IN EFI_DHCP6_PACKET *Dst,
  282. IN EFI_DHCP6_PACKET *Src
  283. )
  284. {
  285. if (Dst->Size < Src->Length) {
  286. return EFI_BUFFER_TOO_SMALL;
  287. }
  288. CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);
  289. Dst->Length = Src->Length;
  290. return EFI_SUCCESS;
  291. }
  292. /**
  293. Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
  294. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  295. @param[in] RcvdOffer The pointer to the received offer packet.
  296. @retval EFI_SUCCESS Cache and parse the packet successfully.
  297. @retval Others Operation failed.
  298. **/
  299. EFI_STATUS
  300. HttpBootCacheDhcp6Offer (
  301. IN HTTP_BOOT_PRIVATE_DATA *Private,
  302. IN EFI_DHCP6_PACKET *RcvdOffer
  303. )
  304. {
  305. HTTP_BOOT_DHCP6_PACKET_CACHE *Cache6;
  306. EFI_DHCP6_PACKET *Offer;
  307. HTTP_BOOT_OFFER_TYPE OfferType;
  308. EFI_STATUS Status;
  309. Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;
  310. Offer = &Cache6->Packet.Offer;
  311. //
  312. // Cache the content of DHCPv6 packet firstly.
  313. //
  314. Status = HttpBootCacheDhcp6Packet(Offer, RcvdOffer);
  315. if (EFI_ERROR (Status)) {
  316. return Status;
  317. }
  318. //
  319. // Validate the DHCPv6 packet, and parse the options and offer type.
  320. //
  321. if (EFI_ERROR (HttpBootParseDhcp6Packet (Cache6))) {
  322. return EFI_ABORTED;
  323. }
  324. //
  325. // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
  326. //
  327. OfferType = Cache6->OfferType;
  328. ASSERT (OfferType < HttpOfferTypeMax);
  329. ASSERT (Private->OfferCount[OfferType] < HTTP_BOOT_OFFER_MAX_NUM);
  330. Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
  331. Private->OfferCount[OfferType]++;
  332. Private->OfferNum++;
  333. return EFI_SUCCESS;
  334. }
  335. /**
  336. EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
  337. to intercept events that occurred in the configuration process.
  338. @param[in] This The pointer to the EFI DHCPv6 Protocol.
  339. @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
  340. @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
  341. @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
  342. state transition.
  343. @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
  344. @param[out] NewPacket The packet that is used to replace the Packet above.
  345. @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
  346. @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
  347. driver will continue to wait for more packets.
  348. @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
  349. @retval EFI_OUT_OF_RESOURCES There are not enough resources.
  350. **/
  351. EFI_STATUS
  352. EFIAPI
  353. HttpBootDhcp6CallBack (
  354. IN EFI_DHCP6_PROTOCOL *This,
  355. IN VOID *Context,
  356. IN EFI_DHCP6_STATE CurrentState,
  357. IN EFI_DHCP6_EVENT Dhcp6Event,
  358. IN EFI_DHCP6_PACKET *Packet,
  359. OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL
  360. )
  361. {
  362. HTTP_BOOT_PRIVATE_DATA *Private;
  363. EFI_DHCP6_PACKET *SelectAd;
  364. EFI_STATUS Status;
  365. BOOLEAN Received;
  366. if ((Dhcp6Event != Dhcp6SendSolicit) &&
  367. (Dhcp6Event != Dhcp6RcvdAdvertise) &&
  368. (Dhcp6Event != Dhcp6SendRequest) &&
  369. (Dhcp6Event != Dhcp6RcvdReply) &&
  370. (Dhcp6Event != Dhcp6SelectAdvertise)) {
  371. return EFI_SUCCESS;
  372. }
  373. ASSERT (Packet != NULL);
  374. Private = (HTTP_BOOT_PRIVATE_DATA *) Context;
  375. Status = EFI_SUCCESS;
  376. if (Private->HttpBootCallback != NULL && Dhcp6Event != Dhcp6SelectAdvertise) {
  377. Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);
  378. Status = Private->HttpBootCallback->Callback (
  379. Private->HttpBootCallback,
  380. HttpBootDhcp6,
  381. Received,
  382. Packet->Length,
  383. &Packet->Dhcp6
  384. );
  385. if (EFI_ERROR (Status)) {
  386. return EFI_ABORTED;
  387. }
  388. }
  389. switch (Dhcp6Event) {
  390. case Dhcp6RcvdAdvertise:
  391. Status = EFI_NOT_READY;
  392. if (Packet->Length > HTTP_BOOT_DHCP6_PACKET_MAX_SIZE) {
  393. //
  394. // Ignore the incoming packets which exceed the maximum length.
  395. //
  396. break;
  397. }
  398. if (Private->OfferNum < HTTP_BOOT_OFFER_MAX_NUM) {
  399. //
  400. // Cache the dhcp offers to OfferBuffer[] for select later, and record
  401. // the OfferIndex and OfferCount.
  402. // If error happens, just ignore this packet and continue to wait more offer.
  403. //
  404. HttpBootCacheDhcp6Offer (Private, Packet);
  405. }
  406. break;
  407. case Dhcp6SelectAdvertise:
  408. //
  409. // Select offer by the default policy or by order, and record the SelectIndex
  410. // and SelectProxyType.
  411. //
  412. HttpBootSelectDhcpOffer (Private);
  413. if (Private->SelectIndex == 0) {
  414. Status = EFI_ABORTED;
  415. } else {
  416. ASSERT (NewPacket != NULL);
  417. SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;
  418. *NewPacket = AllocateZeroPool (SelectAd->Size);
  419. if (*NewPacket == NULL) {
  420. return EFI_OUT_OF_RESOURCES;
  421. }
  422. CopyMem (*NewPacket, SelectAd, SelectAd->Size);
  423. }
  424. break;
  425. default:
  426. break;
  427. }
  428. return Status;
  429. }
  430. /**
  431. Check whether IP driver could route the message which will be sent to ServerIp address.
  432. This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
  433. route is found in IP6 route table, the address will be filed in GatewayAddr and return.
  434. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  435. @param[in] TimeOutInSecond Timeout value in seconds.
  436. @param[out] GatewayAddr Pointer to store the gateway IP address.
  437. @retval EFI_SUCCESS Found a valid gateway address successfully.
  438. @retval EFI_TIMEOUT The operation is time out.
  439. @retval Other Unexpect error happened.
  440. **/
  441. EFI_STATUS
  442. HttpBootCheckRouteTable (
  443. IN HTTP_BOOT_PRIVATE_DATA *Private,
  444. IN UINTN TimeOutInSecond,
  445. OUT EFI_IPv6_ADDRESS *GatewayAddr
  446. )
  447. {
  448. EFI_STATUS Status;
  449. EFI_IP6_PROTOCOL *Ip6;
  450. EFI_IP6_MODE_DATA Ip6ModeData;
  451. UINTN Index;
  452. EFI_EVENT TimeOutEvt;
  453. UINTN RetryCount;
  454. BOOLEAN GatewayIsFound;
  455. ASSERT (GatewayAddr != NULL);
  456. ASSERT (Private != NULL);
  457. Ip6 = Private->Ip6;
  458. GatewayIsFound = FALSE;
  459. RetryCount = 0;
  460. TimeOutEvt = NULL;
  461. Status = EFI_SUCCESS;
  462. ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
  463. while (TRUE) {
  464. Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
  465. if (EFI_ERROR (Status)) {
  466. goto ON_EXIT;
  467. }
  468. //
  469. // Find out the gateway address which can route the message which send to ServerIp.
  470. //
  471. for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
  472. if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
  473. IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
  474. GatewayIsFound = TRUE;
  475. break;
  476. }
  477. }
  478. if (Ip6ModeData.AddressList != NULL) {
  479. FreePool (Ip6ModeData.AddressList);
  480. }
  481. if (Ip6ModeData.GroupTable != NULL) {
  482. FreePool (Ip6ModeData.GroupTable);
  483. }
  484. if (Ip6ModeData.RouteTable != NULL) {
  485. FreePool (Ip6ModeData.RouteTable);
  486. }
  487. if (Ip6ModeData.NeighborCache != NULL) {
  488. FreePool (Ip6ModeData.NeighborCache);
  489. }
  490. if (Ip6ModeData.PrefixTable != NULL) {
  491. FreePool (Ip6ModeData.PrefixTable);
  492. }
  493. if (Ip6ModeData.IcmpTypeList != NULL) {
  494. FreePool (Ip6ModeData.IcmpTypeList);
  495. }
  496. if (GatewayIsFound || RetryCount == TimeOutInSecond) {
  497. break;
  498. }
  499. RetryCount++;
  500. //
  501. // Delay 1 second then recheck it again.
  502. //
  503. if (TimeOutEvt == NULL) {
  504. Status = gBS->CreateEvent (
  505. EVT_TIMER,
  506. TPL_CALLBACK,
  507. NULL,
  508. NULL,
  509. &TimeOutEvt
  510. );
  511. if (EFI_ERROR (Status)) {
  512. goto ON_EXIT;
  513. }
  514. }
  515. Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
  516. if (EFI_ERROR (Status)) {
  517. goto ON_EXIT;
  518. }
  519. while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
  520. Ip6->Poll (Ip6);
  521. }
  522. }
  523. ON_EXIT:
  524. if (TimeOutEvt != NULL) {
  525. gBS->CloseEvent (TimeOutEvt);
  526. }
  527. if (GatewayIsFound) {
  528. Status = EFI_SUCCESS;
  529. } else if (RetryCount == TimeOutInSecond) {
  530. Status = EFI_TIMEOUT;
  531. }
  532. return Status;
  533. }
  534. /**
  535. Set the IP6 policy to Automatic.
  536. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  537. @retval EFI_SUCCESS Switch the IP policy succesfully.
  538. @retval Others Unexpect error happened.
  539. **/
  540. EFI_STATUS
  541. HttpBootSetIp6Policy (
  542. IN HTTP_BOOT_PRIVATE_DATA *Private
  543. )
  544. {
  545. EFI_IP6_CONFIG_POLICY Policy;
  546. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  547. EFI_STATUS Status;
  548. UINTN DataSize;
  549. Ip6Config = Private->Ip6Config;
  550. DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
  551. //
  552. // Get and store the current policy of IP6 driver.
  553. //
  554. Status = Ip6Config->GetData (
  555. Ip6Config,
  556. Ip6ConfigDataTypePolicy,
  557. &DataSize,
  558. &Policy
  559. );
  560. if (EFI_ERROR (Status)) {
  561. return Status;
  562. }
  563. if (Policy == Ip6ConfigPolicyManual) {
  564. Policy = Ip6ConfigPolicyAutomatic;
  565. Status = Ip6Config->SetData (
  566. Ip6Config,
  567. Ip6ConfigDataTypePolicy,
  568. sizeof(EFI_IP6_CONFIG_POLICY),
  569. &Policy
  570. );
  571. if (EFI_ERROR (Status)) {
  572. return Status;
  573. }
  574. }
  575. return EFI_SUCCESS;
  576. }
  577. /**
  578. This function will register the default DNS addresses to the network device.
  579. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  580. @param[in] DataLength Size of the buffer pointed to by DnsServerData in bytes.
  581. @param[in] DnsServerData Point a list of DNS server address in an array
  582. of EFI_IPv6_ADDRESS instances.
  583. @retval EFI_SUCCESS The DNS configuration has been configured successfully.
  584. @retval Others Failed to configure the address.
  585. **/
  586. EFI_STATUS
  587. HttpBootSetIp6Dns (
  588. IN HTTP_BOOT_PRIVATE_DATA *Private,
  589. IN UINTN DataLength,
  590. IN VOID *DnsServerData
  591. )
  592. {
  593. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  594. ASSERT (Private->UsingIpv6);
  595. Ip6Config = Private->Ip6Config;
  596. return Ip6Config->SetData (
  597. Ip6Config,
  598. Ip6ConfigDataTypeDnsServer,
  599. DataLength,
  600. DnsServerData
  601. );
  602. }
  603. /**
  604. This function will register the IPv6 gateway address to the network device.
  605. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  606. @retval EFI_SUCCESS The new IP configuration has been configured successfully.
  607. @retval Others Failed to configure the address.
  608. **/
  609. EFI_STATUS
  610. HttpBootSetIp6Gateway (
  611. IN HTTP_BOOT_PRIVATE_DATA *Private
  612. )
  613. {
  614. EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
  615. EFI_STATUS Status;
  616. ASSERT (Private->UsingIpv6);
  617. Ip6Config = Private->Ip6Config;
  618. //
  619. // Set the default gateway address.
  620. //
  621. if (!Private->NoGateway && !NetIp6IsUnspecifiedAddr (&Private->GatewayIp.v6)) {
  622. Status = Ip6Config->SetData (
  623. Ip6Config,
  624. Ip6ConfigDataTypeGateway,
  625. sizeof (EFI_IPv6_ADDRESS),
  626. &Private->GatewayIp.v6
  627. );
  628. if (EFI_ERROR(Status)) {
  629. return Status;
  630. }
  631. }
  632. return EFI_SUCCESS;
  633. }
  634. /**
  635. This function will register the station IP address.
  636. @param[in] Private The pointer to HTTP_BOOT_PRIVATE_DATA.
  637. @retval EFI_SUCCESS The new IP address has been configured successfully.
  638. @retval Others Failed to configure the address.
  639. **/
  640. EFI_STATUS
  641. HttpBootSetIp6Address (
  642. IN HTTP_BOOT_PRIVATE_DATA *Private
  643. )
  644. {
  645. EFI_STATUS Status;
  646. EFI_IP6_PROTOCOL *Ip6;
  647. EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
  648. EFI_IP6_CONFIG_POLICY Policy;
  649. EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
  650. EFI_IPv6_ADDRESS *Ip6Addr;
  651. EFI_IPv6_ADDRESS GatewayAddr;
  652. EFI_IP6_CONFIG_DATA Ip6CfgData;
  653. EFI_EVENT MappedEvt;
  654. UINTN DataSize;
  655. BOOLEAN IsAddressOk;
  656. UINTN Index;
  657. ASSERT (Private->UsingIpv6);
  658. MappedEvt = NULL;
  659. IsAddressOk = FALSE;
  660. Ip6Addr = NULL;
  661. Ip6Cfg = Private->Ip6Config;
  662. Ip6 = Private->Ip6;
  663. ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
  664. CopyMem (&CfgAddr, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
  665. ZeroMem (&Ip6CfgData, sizeof (EFI_IP6_CONFIG_DATA));
  666. Ip6CfgData.AcceptIcmpErrors = TRUE;
  667. Ip6CfgData.DefaultProtocol = IP6_ICMP;
  668. Ip6CfgData.HopLimit = HTTP_BOOT_DEFAULT_HOPLIMIT;
  669. Ip6CfgData.ReceiveTimeout = HTTP_BOOT_DEFAULT_LIFETIME;
  670. Ip6CfgData.TransmitTimeout = HTTP_BOOT_DEFAULT_LIFETIME;
  671. Status = Ip6->Configure (Ip6, &Ip6CfgData);
  672. if (EFI_ERROR (Status)) {
  673. goto ON_EXIT;
  674. }
  675. //
  676. // Retrieve the gateway address from IP6 route table.
  677. //
  678. Status = HttpBootCheckRouteTable (Private, HTTP_BOOT_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
  679. if (EFI_ERROR (Status)) {
  680. Private->NoGateway = TRUE;
  681. } else {
  682. IP6_COPY_ADDRESS (&Private->GatewayIp.v6, &GatewayAddr);
  683. }
  684. //
  685. // Set the new address by Ip6ConfigProtocol manually.
  686. //
  687. Policy = Ip6ConfigPolicyManual;
  688. Status = Ip6Cfg->SetData (
  689. Ip6Cfg,
  690. Ip6ConfigDataTypePolicy,
  691. sizeof(EFI_IP6_CONFIG_POLICY),
  692. &Policy
  693. );
  694. if (EFI_ERROR (Status)) {
  695. goto ON_EXIT;
  696. }
  697. //
  698. // Create a notify event to set address flag when DAD if IP6 driver succeeded.
  699. //
  700. Status = gBS->CreateEvent (
  701. EVT_NOTIFY_SIGNAL,
  702. TPL_NOTIFY,
  703. HttpBootCommonNotify,
  704. &IsAddressOk,
  705. &MappedEvt
  706. );
  707. if (EFI_ERROR (Status)) {
  708. goto ON_EXIT;
  709. }
  710. //
  711. // Set static host ip6 address. This is a asynchronous process.
  712. //
  713. Status = Ip6Cfg->RegisterDataNotify (
  714. Ip6Cfg,
  715. Ip6ConfigDataTypeManualAddress,
  716. MappedEvt
  717. );
  718. if (EFI_ERROR(Status)) {
  719. goto ON_EXIT;
  720. }
  721. Status = Ip6Cfg->SetData (
  722. Ip6Cfg,
  723. Ip6ConfigDataTypeManualAddress,
  724. sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),
  725. &CfgAddr
  726. );
  727. if (EFI_ERROR (Status) && Status != EFI_NOT_READY) {
  728. goto ON_EXIT;
  729. } else if (Status == EFI_NOT_READY) {
  730. //
  731. // Poll the network until the asynchronous process is finished.
  732. //
  733. while (!IsAddressOk) {
  734. Ip6->Poll (Ip6);
  735. }
  736. //
  737. // Check whether the Ip6 Address setting is successed.
  738. //
  739. DataSize = 0;
  740. Status = Ip6Cfg->GetData (
  741. Ip6Cfg,
  742. Ip6ConfigDataTypeManualAddress,
  743. &DataSize,
  744. NULL
  745. );
  746. if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) {
  747. Status = EFI_DEVICE_ERROR;
  748. goto ON_EXIT;
  749. }
  750. Ip6Addr = AllocatePool (DataSize);
  751. if (Ip6Addr == NULL) {
  752. return EFI_OUT_OF_RESOURCES;
  753. }
  754. Status = Ip6Cfg->GetData (
  755. Ip6Cfg,
  756. Ip6ConfigDataTypeManualAddress,
  757. &DataSize,
  758. (VOID *) Ip6Addr
  759. );
  760. if (EFI_ERROR (Status)) {
  761. Status = EFI_DEVICE_ERROR;
  762. goto ON_EXIT;
  763. }
  764. for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index ++) {
  765. if (CompareMem (Ip6Addr + Index, &CfgAddr, sizeof (EFI_IPv6_ADDRESS)) == 0) {
  766. break;
  767. }
  768. }
  769. if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {
  770. Status = EFI_ABORTED;
  771. goto ON_EXIT;
  772. }
  773. }
  774. ON_EXIT:
  775. if (MappedEvt != NULL) {
  776. Ip6Cfg->UnregisterDataNotify (
  777. Ip6Cfg,
  778. Ip6ConfigDataTypeManualAddress,
  779. MappedEvt
  780. );
  781. gBS->CloseEvent (MappedEvt);
  782. }
  783. if (Ip6Addr != NULL) {
  784. FreePool (Ip6Addr);
  785. }
  786. return Status;
  787. }
  788. /**
  789. Start the S.A.R.R DHCPv6 process to acquire the IPv6 address and other Http boot information.
  790. @param[in] Private Pointer to HTTP_BOOT private data.
  791. @retval EFI_SUCCESS The S.A.R.R process successfully finished.
  792. @retval Others Failed to finish the S.A.R.R process.
  793. **/
  794. EFI_STATUS
  795. HttpBootDhcp6Sarr (
  796. IN HTTP_BOOT_PRIVATE_DATA *Private
  797. )
  798. {
  799. EFI_DHCP6_PROTOCOL *Dhcp6;
  800. EFI_DHCP6_CONFIG_DATA Config;
  801. EFI_DHCP6_MODE_DATA Mode;
  802. EFI_DHCP6_RETRANSMISSION *Retransmit;
  803. EFI_DHCP6_PACKET_OPTION *OptList[HTTP_BOOT_DHCP6_OPTION_MAX_NUM];
  804. UINT32 OptCount;
  805. UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE];
  806. EFI_STATUS Status;
  807. Dhcp6 = Private->Dhcp6;
  808. ASSERT (Dhcp6 != NULL);
  809. //
  810. // Build options list for the request packet.
  811. //
  812. OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer);
  813. ASSERT (OptCount >0);
  814. Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
  815. if (Retransmit == NULL) {
  816. return EFI_OUT_OF_RESOURCES;
  817. }
  818. ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));
  819. ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
  820. Config.OptionCount = OptCount;
  821. Config.OptionList = OptList;
  822. Config.Dhcp6Callback = HttpBootDhcp6CallBack;
  823. Config.CallbackContext = Private;
  824. Config.IaInfoEvent = NULL;
  825. Config.RapidCommit = FALSE;
  826. Config.ReconfigureAccept = FALSE;
  827. Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ());
  828. Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
  829. Config.SolicitRetransmission = Retransmit;
  830. Retransmit->Irt = 4;
  831. Retransmit->Mrc = 4;
  832. Retransmit->Mrt = 32;
  833. Retransmit->Mrd = 60;
  834. //
  835. // Configure the DHCPv6 instance for HTTP boot.
  836. //
  837. Status = Dhcp6->Configure (Dhcp6, &Config);
  838. FreePool (Retransmit);
  839. if (EFI_ERROR (Status)) {
  840. goto ON_EXIT;
  841. }
  842. //
  843. // Initialize the record fields for DHCPv6 offer in private data.
  844. //
  845. Private->OfferNum = 0;
  846. Private->SelectIndex = 0;
  847. ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
  848. ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
  849. //
  850. // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
  851. //
  852. Status = Dhcp6->Start (Dhcp6);
  853. if (EFI_ERROR (Status)) {
  854. goto ON_EXIT;
  855. }
  856. //
  857. // Get the acquired IPv6 address and store them.
  858. //
  859. Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);
  860. if (EFI_ERROR (Status)) {
  861. goto ON_EXIT;
  862. }
  863. ASSERT (Mode.Ia->State == Dhcp6Bound);
  864. CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
  865. AsciiPrint ("\n Station IPv6 address is ");
  866. HttpBootShowIp6Addr (&Private->StationIp.v6);
  867. AsciiPrint ("\n");
  868. ON_EXIT:
  869. if (EFI_ERROR (Status)) {
  870. Dhcp6->Stop (Dhcp6);
  871. Dhcp6->Configure (Dhcp6, NULL);
  872. } else {
  873. ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
  874. Dhcp6->Configure (Dhcp6, &Config);
  875. if (Mode.ClientId != NULL) {
  876. FreePool (Mode.ClientId);
  877. }
  878. if (Mode.Ia != NULL) {
  879. FreePool (Mode.Ia);
  880. }
  881. }
  882. return Status;
  883. }