DnsDhcp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /** @file
  2. Functions implementation related with DHCPv4/v6 for DNS driver.
  3. Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "DnsImpl.h"
  7. /**
  8. This function initialize the DHCP4 message instance.
  9. This function will pad each item of dhcp4 message packet.
  10. @param Seed Pointer to the message instance of the DHCP4 packet.
  11. @param InterfaceInfo Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
  12. **/
  13. VOID
  14. DnsInitSeedPacket (
  15. OUT EFI_DHCP4_PACKET *Seed,
  16. IN EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo
  17. )
  18. {
  19. EFI_DHCP4_HEADER *Header;
  20. //
  21. // Get IfType and HwAddressSize from SNP mode data.
  22. //
  23. Seed->Size = sizeof (EFI_DHCP4_PACKET);
  24. Seed->Length = sizeof (Seed->Dhcp4);
  25. Header = &Seed->Dhcp4.Header;
  26. ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
  27. Header->OpCode = DHCP4_OPCODE_REQUEST;
  28. Header->HwType = InterfaceInfo->IfType;
  29. Header->HwAddrLen = (UINT8)InterfaceInfo->HwAddressSize;
  30. CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);
  31. Seed->Dhcp4.Magik = DHCP4_MAGIC;
  32. Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
  33. }
  34. /**
  35. The common notify function.
  36. @param[in] Event The event signaled.
  37. @param[in] Context The context.
  38. **/
  39. VOID
  40. EFIAPI
  41. DhcpCommonNotify (
  42. IN EFI_EVENT Event,
  43. IN VOID *Context
  44. )
  45. {
  46. if ((Event == NULL) || (Context == NULL)) {
  47. return;
  48. }
  49. *((BOOLEAN *)Context) = TRUE;
  50. }
  51. /**
  52. Parse the ACK to get required information
  53. @param Dhcp4 The DHCP4 protocol.
  54. @param Packet Packet waiting for parse.
  55. @param DnsServerInfor The required Dns4 server information.
  56. @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
  57. @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
  58. @retval EFI_DEVICE_ERROR Other errors as indicated.
  59. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  60. **/
  61. EFI_STATUS
  62. ParseDhcp4Ack (
  63. IN EFI_DHCP4_PROTOCOL *Dhcp4,
  64. IN EFI_DHCP4_PACKET *Packet,
  65. IN DNS4_SERVER_INFOR *DnsServerInfor
  66. )
  67. {
  68. EFI_STATUS Status;
  69. UINT32 OptionCount;
  70. EFI_DHCP4_PACKET_OPTION **OptionList;
  71. UINT32 ServerCount;
  72. EFI_IPv4_ADDRESS *ServerList;
  73. UINT32 Index;
  74. UINT32 Count;
  75. ServerCount = 0;
  76. ServerList = NULL;
  77. OptionCount = 0;
  78. OptionList = NULL;
  79. Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
  80. if (Status != EFI_BUFFER_TOO_SMALL) {
  81. return EFI_DEVICE_ERROR;
  82. }
  83. OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
  84. if (OptionList == NULL) {
  85. return EFI_OUT_OF_RESOURCES;
  86. }
  87. Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
  88. if (EFI_ERROR (Status)) {
  89. gBS->FreePool (OptionList);
  90. return EFI_DEVICE_ERROR;
  91. }
  92. Status = EFI_NOT_FOUND;
  93. for (Index = 0; Index < OptionCount; Index++) {
  94. //
  95. // Get DNS server addresses
  96. //
  97. if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
  98. if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
  99. Status = EFI_DEVICE_ERROR;
  100. break;
  101. }
  102. ServerCount = OptionList[Index]->Length/4;
  103. ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));
  104. if (ServerList == NULL) {
  105. return EFI_OUT_OF_RESOURCES;
  106. }
  107. for (Count = 0; Count < ServerCount; Count++) {
  108. CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));
  109. }
  110. *(DnsServerInfor->ServerCount) = ServerCount;
  111. DnsServerInfor->ServerList = ServerList;
  112. Status = EFI_SUCCESS;
  113. }
  114. }
  115. gBS->FreePool (OptionList);
  116. return Status;
  117. }
  118. /**
  119. EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
  120. instance to intercept events that occurs in the DHCPv6 Information Request
  121. exchange process.
  122. @param This Pointer to the EFI_DHCP6_PROTOCOL instance that
  123. is used to configure this callback function.
  124. @param Context Pointer to the context that is initialized in
  125. the EFI_DHCP6_PROTOCOL.InfoRequest().
  126. @param Packet Pointer to Reply packet that has been received.
  127. The EFI DHCPv6 Protocol instance is responsible
  128. for freeing the buffer.
  129. @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
  130. @retval EFI_DEVICE_ERROR Other errors as indicated.
  131. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  132. **/
  133. EFI_STATUS
  134. EFIAPI
  135. ParseDhcp6Ack (
  136. IN EFI_DHCP6_PROTOCOL *This,
  137. IN VOID *Context,
  138. IN EFI_DHCP6_PACKET *Packet
  139. )
  140. {
  141. EFI_STATUS Status;
  142. UINT32 OptionCount;
  143. EFI_DHCP6_PACKET_OPTION **OptionList;
  144. DNS6_SERVER_INFOR *DnsServerInfor;
  145. UINT32 ServerCount;
  146. EFI_IPv6_ADDRESS *ServerList;
  147. UINT32 Index;
  148. UINT32 Count;
  149. OptionCount = 0;
  150. ServerCount = 0;
  151. ServerList = NULL;
  152. Status = This->Parse (This, Packet, &OptionCount, NULL);
  153. if (Status != EFI_BUFFER_TOO_SMALL) {
  154. return EFI_DEVICE_ERROR;
  155. }
  156. OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
  157. if (OptionList == NULL) {
  158. return EFI_OUT_OF_RESOURCES;
  159. }
  160. Status = This->Parse (This, Packet, &OptionCount, OptionList);
  161. if (EFI_ERROR (Status)) {
  162. gBS->FreePool (OptionList);
  163. return EFI_DEVICE_ERROR;
  164. }
  165. DnsServerInfor = (DNS6_SERVER_INFOR *)Context;
  166. for (Index = 0; Index < OptionCount; Index++) {
  167. OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
  168. OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
  169. //
  170. // Get DNS server addresses from this reply packet.
  171. //
  172. if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {
  173. if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
  174. Status = EFI_DEVICE_ERROR;
  175. gBS->FreePool (OptionList);
  176. return Status;
  177. }
  178. ServerCount = OptionList[Index]->OpLen/16;
  179. ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));
  180. if (ServerList == NULL) {
  181. gBS->FreePool (OptionList);
  182. return EFI_OUT_OF_RESOURCES;
  183. }
  184. for (Count = 0; Count < ServerCount; Count++) {
  185. CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));
  186. }
  187. *(DnsServerInfor->ServerCount) = ServerCount;
  188. DnsServerInfor->ServerList = ServerList;
  189. }
  190. }
  191. gBS->FreePool (OptionList);
  192. return Status;
  193. }
  194. /**
  195. Parse the DHCP ACK to get Dns4 server information.
  196. @param Instance The DNS instance.
  197. @param DnsServerCount Retrieved Dns4 server Ip count.
  198. @param DnsServerList Retrieved Dns4 server Ip list.
  199. @retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK.
  200. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  201. @retval EFI_NO_MEDIA There was a media error.
  202. @retval Others Other errors as indicated.
  203. **/
  204. EFI_STATUS
  205. GetDns4ServerFromDhcp4 (
  206. IN DNS_INSTANCE *Instance,
  207. OUT UINT32 *DnsServerCount,
  208. OUT EFI_IPv4_ADDRESS **DnsServerList
  209. )
  210. {
  211. EFI_STATUS Status;
  212. EFI_HANDLE Image;
  213. EFI_HANDLE Controller;
  214. EFI_STATUS MediaStatus;
  215. EFI_HANDLE MnpChildHandle;
  216. EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
  217. EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
  218. EFI_HANDLE Dhcp4Handle;
  219. EFI_DHCP4_PROTOCOL *Dhcp4;
  220. EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
  221. UINTN DataSize;
  222. VOID *Data;
  223. EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo;
  224. EFI_DHCP4_PACKET SeedPacket;
  225. EFI_DHCP4_PACKET_OPTION *ParaList[2];
  226. DNS4_SERVER_INFOR DnsServerInfor;
  227. EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
  228. BOOLEAN IsDone;
  229. UINTN Index;
  230. Image = Instance->Service->ImageHandle;
  231. Controller = Instance->Service->ControllerHandle;
  232. MnpChildHandle = NULL;
  233. Mnp = NULL;
  234. Dhcp4Handle = NULL;
  235. Dhcp4 = NULL;
  236. Ip4Config2 = NULL;
  237. DataSize = 0;
  238. Data = NULL;
  239. InterfaceInfo = NULL;
  240. ZeroMem ((UINT8 *)ParaList, sizeof (ParaList));
  241. ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
  242. ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
  243. ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
  244. DnsServerInfor.ServerCount = DnsServerCount;
  245. IsDone = FALSE;
  246. //
  247. // Check media.
  248. //
  249. MediaStatus = EFI_SUCCESS;
  250. NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
  251. if (MediaStatus != EFI_SUCCESS) {
  252. return EFI_NO_MEDIA;
  253. }
  254. //
  255. // Create a Mnp child instance, get the protocol and config for it.
  256. //
  257. Status = NetLibCreateServiceChild (
  258. Controller,
  259. Image,
  260. &gEfiManagedNetworkServiceBindingProtocolGuid,
  261. &MnpChildHandle
  262. );
  263. if (EFI_ERROR (Status)) {
  264. return Status;
  265. }
  266. Status = gBS->OpenProtocol (
  267. MnpChildHandle,
  268. &gEfiManagedNetworkProtocolGuid,
  269. (VOID **)&Mnp,
  270. Image,
  271. Controller,
  272. EFI_OPEN_PROTOCOL_BY_DRIVER
  273. );
  274. if (EFI_ERROR (Status)) {
  275. goto ON_EXIT;
  276. }
  277. MnpConfigData.ReceivedQueueTimeoutValue = 0;
  278. MnpConfigData.TransmitQueueTimeoutValue = 0;
  279. MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
  280. MnpConfigData.EnableUnicastReceive = TRUE;
  281. MnpConfigData.EnableMulticastReceive = TRUE;
  282. MnpConfigData.EnableBroadcastReceive = TRUE;
  283. MnpConfigData.EnablePromiscuousReceive = FALSE;
  284. MnpConfigData.FlushQueuesOnReset = TRUE;
  285. MnpConfigData.EnableReceiveTimestamps = FALSE;
  286. MnpConfigData.DisableBackgroundPolling = FALSE;
  287. Status = Mnp->Configure (Mnp, &MnpConfigData);
  288. if (EFI_ERROR (Status)) {
  289. goto ON_EXIT;
  290. }
  291. //
  292. // Create a DHCP4 child instance and get the protocol.
  293. //
  294. Status = NetLibCreateServiceChild (
  295. Controller,
  296. Image,
  297. &gEfiDhcp4ServiceBindingProtocolGuid,
  298. &Dhcp4Handle
  299. );
  300. if (EFI_ERROR (Status)) {
  301. goto ON_EXIT;
  302. }
  303. Status = gBS->OpenProtocol (
  304. Dhcp4Handle,
  305. &gEfiDhcp4ProtocolGuid,
  306. (VOID **)&Dhcp4,
  307. Image,
  308. Controller,
  309. EFI_OPEN_PROTOCOL_BY_DRIVER
  310. );
  311. if (EFI_ERROR (Status)) {
  312. goto ON_EXIT;
  313. }
  314. //
  315. // Get Ip4Config2 instance info.
  316. //
  317. Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **)&Ip4Config2);
  318. if (EFI_ERROR (Status)) {
  319. goto ON_EXIT;
  320. }
  321. Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
  322. if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
  323. goto ON_EXIT;
  324. }
  325. Data = AllocateZeroPool (DataSize);
  326. if (Data == NULL) {
  327. Status = EFI_OUT_OF_RESOURCES;
  328. goto ON_EXIT;
  329. }
  330. Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
  331. if (EFI_ERROR (Status)) {
  332. goto ON_EXIT;
  333. }
  334. InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
  335. //
  336. // Build required Token.
  337. //
  338. Status = gBS->CreateEvent (
  339. EVT_NOTIFY_SIGNAL,
  340. TPL_NOTIFY,
  341. DhcpCommonNotify,
  342. &IsDone,
  343. &Token.CompletionEvent
  344. );
  345. if (EFI_ERROR (Status)) {
  346. goto ON_EXIT;
  347. }
  348. SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
  349. Token.RemotePort = 67;
  350. Token.ListenPointCount = 1;
  351. Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
  352. if (Token.ListenPoints == NULL) {
  353. Status = EFI_OUT_OF_RESOURCES;
  354. goto ON_EXIT;
  355. }
  356. if (Instance->Dns4CfgData.UseDefaultSetting) {
  357. CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
  358. CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
  359. } else {
  360. CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
  361. CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
  362. }
  363. Token.ListenPoints[0].ListenPort = 68;
  364. Token.TimeoutValue = DNS_TIME_TO_GETMAP;
  365. DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
  366. ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
  367. if (ParaList[0] == NULL) {
  368. Status = EFI_OUT_OF_RESOURCES;
  369. goto ON_EXIT;
  370. }
  371. ParaList[0]->OpCode = DHCP4_TAG_TYPE;
  372. ParaList[0]->Length = 1;
  373. ParaList[0]->Data[0] = DHCP4_MSG_REQUEST;
  374. ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
  375. if (ParaList[1] == NULL) {
  376. Status = EFI_OUT_OF_RESOURCES;
  377. goto ON_EXIT;
  378. }
  379. ParaList[1]->OpCode = DHCP4_TAG_PARA_LIST;
  380. ParaList[1]->Length = 1;
  381. ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
  382. Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
  383. Token.Packet->Dhcp4.Header.Xid = HTONL (NET_RANDOM (NetRandomInitSeed ()));
  384. Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
  385. if (Instance->Dns4CfgData.UseDefaultSetting) {
  386. CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
  387. } else {
  388. CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
  389. }
  390. CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
  391. Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
  392. //
  393. // TransmitReceive Token
  394. //
  395. Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
  396. if (EFI_ERROR (Status)) {
  397. goto ON_EXIT;
  398. }
  399. //
  400. // Poll the packet
  401. //
  402. do {
  403. Status = Mnp->Poll (Mnp);
  404. } while (!IsDone);
  405. //
  406. // Parse the ACK to get required information if received done.
  407. //
  408. if (IsDone && !EFI_ERROR (Token.Status)) {
  409. for (Index = 0; Index < Token.ResponseCount; Index++) {
  410. Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
  411. if (!EFI_ERROR (Status)) {
  412. break;
  413. }
  414. }
  415. *DnsServerList = DnsServerInfor.ServerList;
  416. } else {
  417. Status = Token.Status;
  418. }
  419. ON_EXIT:
  420. if (Data != NULL) {
  421. FreePool (Data);
  422. }
  423. for (Index = 0; Index < 2; Index++) {
  424. if (ParaList[Index] != NULL) {
  425. FreePool (ParaList[Index]);
  426. }
  427. }
  428. if (Token.ListenPoints) {
  429. FreePool (Token.ListenPoints);
  430. }
  431. if (Token.Packet) {
  432. FreePool (Token.Packet);
  433. }
  434. if (Token.ResponseList != NULL) {
  435. FreePool (Token.ResponseList);
  436. }
  437. if (Token.CompletionEvent != NULL) {
  438. gBS->CloseEvent (Token.CompletionEvent);
  439. }
  440. if (Dhcp4 != NULL) {
  441. Dhcp4->Stop (Dhcp4);
  442. Dhcp4->Configure (Dhcp4, NULL);
  443. gBS->CloseProtocol (
  444. Dhcp4Handle,
  445. &gEfiDhcp4ProtocolGuid,
  446. Image,
  447. Controller
  448. );
  449. }
  450. if (Dhcp4Handle != NULL) {
  451. NetLibDestroyServiceChild (
  452. Controller,
  453. Image,
  454. &gEfiDhcp4ServiceBindingProtocolGuid,
  455. Dhcp4Handle
  456. );
  457. }
  458. if (Mnp != NULL) {
  459. Mnp->Configure (Mnp, NULL);
  460. gBS->CloseProtocol (
  461. MnpChildHandle,
  462. &gEfiManagedNetworkProtocolGuid,
  463. Image,
  464. Controller
  465. );
  466. }
  467. NetLibDestroyServiceChild (
  468. Controller,
  469. Image,
  470. &gEfiManagedNetworkServiceBindingProtocolGuid,
  471. MnpChildHandle
  472. );
  473. return Status;
  474. }
  475. /**
  476. Parse the DHCP ACK to get Dns6 server information.
  477. @param Image The handle of the driver image.
  478. @param Controller The handle of the controller.
  479. @param DnsServerCount Retrieved Dns6 server Ip count.
  480. @param DnsServerList Retrieved Dns6 server Ip list.
  481. @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK.
  482. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  483. @retval EFI_NO_MEDIA There was a media error.
  484. @retval Others Other errors as indicated.
  485. **/
  486. EFI_STATUS
  487. GetDns6ServerFromDhcp6 (
  488. IN EFI_HANDLE Image,
  489. IN EFI_HANDLE Controller,
  490. OUT UINT32 *DnsServerCount,
  491. OUT EFI_IPv6_ADDRESS **DnsServerList
  492. )
  493. {
  494. EFI_HANDLE Dhcp6Handle;
  495. EFI_DHCP6_PROTOCOL *Dhcp6;
  496. EFI_STATUS Status;
  497. EFI_STATUS TimerStatus;
  498. EFI_DHCP6_PACKET_OPTION *Oro;
  499. EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
  500. EFI_EVENT Timer;
  501. EFI_STATUS MediaStatus;
  502. DNS6_SERVER_INFOR DnsServerInfor;
  503. Dhcp6Handle = NULL;
  504. Dhcp6 = NULL;
  505. Oro = NULL;
  506. Timer = NULL;
  507. ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
  508. DnsServerInfor.ServerCount = DnsServerCount;
  509. //
  510. // Check media status before doing DHCP.
  511. //
  512. MediaStatus = EFI_SUCCESS;
  513. NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
  514. if (MediaStatus != EFI_SUCCESS) {
  515. return EFI_NO_MEDIA;
  516. }
  517. //
  518. // Create a DHCP6 child instance and get the protocol.
  519. //
  520. Status = NetLibCreateServiceChild (
  521. Controller,
  522. Image,
  523. &gEfiDhcp6ServiceBindingProtocolGuid,
  524. &Dhcp6Handle
  525. );
  526. if (EFI_ERROR (Status)) {
  527. return Status;
  528. }
  529. Status = gBS->OpenProtocol (
  530. Dhcp6Handle,
  531. &gEfiDhcp6ProtocolGuid,
  532. (VOID **)&Dhcp6,
  533. Image,
  534. Controller,
  535. EFI_OPEN_PROTOCOL_BY_DRIVER
  536. );
  537. if (EFI_ERROR (Status)) {
  538. goto ON_EXIT;
  539. }
  540. Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
  541. if (Oro == NULL) {
  542. Status = EFI_OUT_OF_RESOURCES;
  543. goto ON_EXIT;
  544. }
  545. //
  546. // Ask the server to reply with DNS options.
  547. // All members in EFI_DHCP6_PACKET_OPTION are in network order.
  548. //
  549. Oro->OpCode = HTONS (DHCP6_TAG_DNS_REQUEST);
  550. Oro->OpLen = HTONS (2);
  551. Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
  552. InfoReqReXmit.Irt = 4;
  553. InfoReqReXmit.Mrc = 1;
  554. InfoReqReXmit.Mrt = 10;
  555. InfoReqReXmit.Mrd = 30;
  556. Status = Dhcp6->InfoRequest (
  557. Dhcp6,
  558. TRUE,
  559. Oro,
  560. 0,
  561. NULL,
  562. &InfoReqReXmit,
  563. NULL,
  564. ParseDhcp6Ack,
  565. &DnsServerInfor
  566. );
  567. if (Status == EFI_NO_MAPPING) {
  568. Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
  569. if (EFI_ERROR (Status)) {
  570. goto ON_EXIT;
  571. }
  572. Status = gBS->SetTimer (
  573. Timer,
  574. TimerRelative,
  575. DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
  576. );
  577. if (EFI_ERROR (Status)) {
  578. goto ON_EXIT;
  579. }
  580. do {
  581. TimerStatus = gBS->CheckEvent (Timer);
  582. if (!EFI_ERROR (TimerStatus)) {
  583. Status = Dhcp6->InfoRequest (
  584. Dhcp6,
  585. TRUE,
  586. Oro,
  587. 0,
  588. NULL,
  589. &InfoReqReXmit,
  590. NULL,
  591. ParseDhcp6Ack,
  592. &DnsServerInfor
  593. );
  594. }
  595. } while (TimerStatus == EFI_NOT_READY);
  596. }
  597. *DnsServerList = DnsServerInfor.ServerList;
  598. ON_EXIT:
  599. if (Oro != NULL) {
  600. FreePool (Oro);
  601. }
  602. if (Timer != NULL) {
  603. gBS->CloseEvent (Timer);
  604. }
  605. if (Dhcp6 != NULL) {
  606. gBS->CloseProtocol (
  607. Dhcp6Handle,
  608. &gEfiDhcp6ProtocolGuid,
  609. Image,
  610. Controller
  611. );
  612. }
  613. NetLibDestroyServiceChild (
  614. Controller,
  615. Image,
  616. &gEfiDhcp6ServiceBindingProtocolGuid,
  617. Dhcp6Handle
  618. );
  619. return Status;
  620. }